Mybatis源码分析-StatementHandler
承接前文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的更多相关文章
- 精尽MyBatis源码分析 - SQL执行过程(二)之 StatementHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- MyBatis源码分析-SQL语句执行的完整流程
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- MyBatis源码分析(2)—— Plugin原理
@(MyBatis)[Plugin] MyBatis源码分析--Plugin原理 Plugin原理 Plugin的实现采用了Java的动态代理,应用了责任链设计模式 InterceptorChain ...
- 【MyBatis源码分析】select源码分析及小结
示例代码 之前的文章说过,对于MyBatis来说insert.update.delete是一组的,因为对于MyBatis来说它们都是update:select是一组的,因为对于MyBatis来说它就是 ...
- Mybatis源码分析-BaseExecutor
根据前文Mybatis源码分析-SqlSessionTemplate的简单分析,对于SqlSession的CURD操作都需要经过Executor接口的update/query方法,本文将分析下Base ...
- MyBatis 源码分析系列文章合集
1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...
- MyBatis 源码分析 - 插件机制
1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- Mybatis源码分析
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
随机推荐
- jQuery怎样判断按钮是否被选中
方法一: if ($("#checkbox-id")get(0).checked) { // do something } 方法二: if($('#checkbox-id' ...
- 4.jsp的内置对象
1.jsp有九大内置对象 out request response session application page pagecontext exception config 2.用户发请求 requ ...
- workday2
今天是实习的第二天 看了一天对smarty模板的介绍,进一步加深了对mvc框架的理解,但是对model认识还是非常的模糊的,可能是之前做的一些项目都是比较小的 对比laravel5,smarty模板显 ...
- Python3中的模块
模块使用哪种语言实现并不重要,因为所有的模块导入与使用的方式都相同. 1.常用模块导入格式: import importable1,importable2,... import importable ...
- 实现一个简单的Log框架
实际上算不上框架,只是自己对日志框架的一点理解. 核心接口:Logger,供调用者完成不同等级的日志输出 package com.lichmama.log.service; public interf ...
- 水题 第三站 HDU Largest prime factor
先写一遍思路,跟素数表很类似吧. 1)从小到大遍历数据范围内的所有数.把包含质因子的数的位置都设成跟质因子的位置相同. 2)同一个数的位置可能被多次复写.但是由于是从小到大遍历,这就保证了最后一次写入 ...
- Redis Pipeline原理分析
转载请注明出处:http://www.cnblogs.com/jabnih/ 1. 基本原理 1.1 为什么会出现Pipeline Redis本身是基于Request/Response协议的,正常情况 ...
- 《JavaScript高级程序设计》 -- 变量、作用域和内存问题(二)
1.基本类型与引用类型 基本类型:值保存在变量中 (Number.String.Boolean.Undefined.Null).在内存中占据固定大小空间,被保存在栈内存中 引用类型:值是保存在内存中的 ...
- Redis 错误1067:进程意外终止,Redis不能启动,Redis启动不了
Redis 错误1067:进程意外终止,Redis不能启动,Redis启动不了 >>>>>>>>>>>>>>> ...
- 取一个整数a从右端开始的4~7位
题目:取一个整数a从右端开始的4-7位. 程序分析:可以这样考虑: (1)先使a右移4位. (2)设置一个低4位全为1,其余全为0的数.可用~(~0 < <4) (3)将上面二者进行&am ...