承接前文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. iOS 本地视频和网络视频流播放

    需求:最近公司需要做一个楼宇对讲的功能:门口机(连接WIFI)拨号对室内机(对应的WIFI)的设备进行呼叫,室内机收到呼叫之后将对收到的数据进行UDP广播的转发,手机(连接对应的WIFI)收到视频流之 ...

  2. Linux 压缩 与解压命令

    tar命令 解包:tar zxvf FileName.tar 打包:tar czvf FileName.tar DirName gz命令 解压1:gunzip FileName.gz 解压2:gzip ...

  3. ReadAndWriteData

    /** * 读取和写入不同基本类型数据 * * @throws IOException */ public static void main(String[] args) throws IOExcep ...

  4. Java 9 揭秘(9. 打破模块封装)

    Tips 做一个终身学习的人. 在此章节中,主要介绍以下内容: 什么是打破模块的封装 如何使用命令行选项将依赖项(添加需要)添加到模块 如何使用--add-exports命令行选项导出模块的未导出包, ...

  5. Servlet端 接收不到4096,8192长度的JSON参数

    Servlet端的日志显示,客户端传过来的JSON参数是空值. 但是在客户端的日志显示,已将JSON参数传送过去. 经调查发现,加减1位后的JSON参数均可以正常传送. 只有8192,4096长度的J ...

  6. Tomcat解压版配置详解(Tomcat8示例)

    注:请在JDK安装后操作以下内容 1.  下载Tomcat解压缩安装包 http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.0.45/bin/apac ...

  7. Java系列 – 用Java8新特性进行Java开发太爽了(续)

    本人博客文章网址:https://www.peretang.com/using-java8s-new-features-to-coding-is-awesome-2/ 前言 上周, 我们谈论了关于Ja ...

  8. 关于delete使用limit的一些注意事项

    在使用delete删除记录时,如果表里面存在多条相同的记录,但是此刻你只想删除一条记录,那么limit就派上了用场.但是使用limit的时候得注意: 如图,您如果想着删除第一个名字叫做张三的,如果你这 ...

  9. 计算BMI

    用一个小程序计算BMI 代码如下: package Day06; public class BMI { private String name; private int age; private do ...

  10. 基于android的语音质量评估

    最近研究如何通过android评估通话质量,希望获取的参数有:(1)接通时长 (2)掉话次数 (3)语音是否清晰,以下将给出接通时长和掉话次数的详细定义: 接通时长:通话一方开始拨号到另一方开始振铃的 ...