承接前文Mybatis源码分析-BaseExecutor,本文则对通过StatementHandler接口完成数据库的CRUD操作作简单的分析

StatementHandler#接口列表

  //获取Statement对象,供操作数据库
Statement prepare(Connection connection)
throws SQLException; //参数配置
void parameterize(Statement statement)
throws SQLException; //批处理
void batch(Statement statement)
throws SQLException; //更新操作
int update(Statement statement)
throws SQLException; //查询操作
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException; //获取绑定的sql信息,包含sql语句
BoundSql getBoundSql(); //获取参数处理类,处理参数的映射等
ParameterHandler getParameterHandler();

RoutingStatementHandler-代理委托类

其基本是间接类,只是根据statementType类型创建不同的StatementHandler类,达到适配的效果。此处我们只需要观察它的构造函数

  public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据mappedStatement中的statementType类型来进行委托类的创建
//默认都是PrepareStatementHandler
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
} }

mybatis在某语句不指定statementType属性的情况下,默认创建PrepareStatementHandler

BaseStatementHandler-基本抽象实现类

BaseStatementHandler-构造函数

瞧下代码

  protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
//java类型处理类
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
//此处兼容doUpdate()方法的调用,因为传过来的boundSql为null
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
} this.boundSql = boundSql;
//paramterMap/resultType属性对应的入参集合处理
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
//resultMap/resultType属性对应的出参集合处理
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

BaseStatementHandler#prepare()-创建sql表达式对象statement

具体源码如下

  public Statement prepare(Connection connection) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
//创建表达式对象,供子类复写
statement = instantiateStatement(connection);
//设置执行sql的超时时间
setStatementTimeout(statement);
//通过mappedStatement对象设置statement的fetchSize大小
setFetchSize(statement);
return statement;
}//出现异常则关闭表达式对象
catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}

此处我们只需要关注子类对instantiateStatement()方法的复写,其余的是设置执行sql超时时间、设置statement的fetchSize大小

我们以mybatis默认的PrepareStatementHandler为例

PrepareStatementHandler-预表达式帮助类

PrepareStatementHandler#instantiateStatement()-创建Statement对象

创建的对象为PrepareStatement,具体源码如下

  protected Statement instantiateStatement(Connection connection) throws SQLException {
//获取待执行的sql语句
String sql = boundSql.getSql();
//主键列设置,一般此处针对insert语句
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
}//ResultSet返回类型,默认为空
else if (mappedStatement.getResultSetType() != null) {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareStatement(sql);
}
}

PrepareStatementHandler#update()-CUD操作入口

源码奉上

  public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
//对增删改都会返回执行成功的记录数目
int rows = ps.getUpdateCount();
//针对key进行处理
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}

PrepareStatementHandler#query()-R操作入口

源码奉上

  public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
//对select语句返回的resultMap/resultType进行相应的映射
return resultSetHandler.<E> handleResultSets(ps);
}

小结

  • mybatis对jdbc调用数据库的方式进行了封装,实质都是调用Statement对象来执行sql语句,掌握纯jdbc访问数据库是最基本的

  • MappedStatement对象包含的内容很多,用于数据库访问的有statementType、keyGenerator、resultSetType等属性,具体的读者可自行查阅XMLStatementBuilder#parseStatementNode()源码

Mybatis源码分析-StatementHandler的更多相关文章

  1. 精尽MyBatis源码分析 - SQL执行过程(二)之 StatementHandler

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  2. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  3. MyBatis源码分析(2)—— Plugin原理

    @(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...

  4. 【MyBatis源码分析】select源码分析及小结

    示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...

  5. Mybatis源码分析-BaseExecutor

    根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...

  6. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  7. MyBatis 源码分析 - 插件机制

    1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...

  8. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  9. Mybatis源码分析

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

随机推荐

  1. 解决SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT 'OpenRowset/OpenDatasource' 的访问

    根据需要进行asp.net的数据导入导出,结果报以下错: mark-1: [报错]SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT ...

  2. ASP.NET Core Web API 最小化项目

    ASP.NET Core中默认的ASP.NET Core 模板中有Web API 模板可以创建Web API项目. 有时,只需要创建一个API,不需要关心Razor,本地化或XML序列化.通过删除无用 ...

  3. Python查看MQ队列深度

    分享一段代码,很简单但是也很实用. #!/usr/bin/python #-*- coding:gb18030 -*- ''' Usage: mq.py [Qmgr] *get the queues' ...

  4. usaco training 4.1.2 Fence Rails 题解

    Fence Rails题解 Burch, Kolstad, and Schrijvers Farmer John is trying to erect a fence around part of h ...

  5. C#传入一个时间值,判断年月日时分秒

    /// <summary> /// 功能:某张表的一个时间字段更新的时间停止了多久(和数据库现在的时间比较) /// keyname:数据库参数 ///BGDataService.Quer ...

  6. Mac之OS系统下搭建JavaEE环境 <三> 之Eclipse 与 IntelliJ IDEA 的安装配置

    三.Eclipse 与 IntelliJ IDEA 的安装配置 1.Eclipse的安装配置 1 下载eclipse 到官网 https://www.eclipse.org/downloads/ecl ...

  7. vue基础01

    事件 事件绑定 在vue中,事件绑定用v-on.v-on也可以用@click=""形式 实例1: <div class="container" id=&q ...

  8. 一个简单的java贷款程序

    代码如下: //计算贷款package ClassDemo;import javax.swing.JOptionPane; public class ComputeLoan { public stat ...

  9. java宠物练习

    先定一个宠物的抽象类,把所有共有的属性方法放到次类中,用于子类去继承实现. package backing2; abstract public class pet { private String n ...

  10. 富文本编辑器UEditor自定义工具栏(二、插入图片、音频、视频个性化功能按钮和弹层及自定义分页符)

    导读:本篇将简单探讨插入图片.音频.视频的功能按钮实现方式 传送门:富文本编辑器UEditor自定义工具栏(一.基础配置与字体.背景色.行间距.超链接实现) 一.效果图 1.UEditor自定义工具栏 ...