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使用简 ...
随机推荐
- CSS样式表之常用文本属性
断更了两周了,因为纠结之后在学java啦,但是还是要把学过的前端知识更完 以下的一些文本属性是CSS最常用的属性: [长度单位]:px(像素) [颜色单位]: 十六进制:#ffffff 分别对应红绿蓝 ...
- 测试框架:使用SONAR分析代码质量
介绍 Sonar是一个用于代码质量管理的开源平台,用于管理Java源代码的质量.通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具,比如pmd-cpd.checkstyl ...
- 【使用WCF,发布服务端浏览报错】未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” 中加载类型 “System.ServiceModel.Activation.HttpModule”。
问题: 在WIN7中的IIS服务器中部署WCF服务程序时,通过浏览器访问报出如下错误: 未能从程序集"System.ServiceModel, Version=3.0.0.0, Cultur ...
- 學習 DT device tree 以 ST 的開發板 STM32F429i-disc1 為例
目標 因為對 device tree 不是很熟悉, 所以就將 device tree, 設為學習目標. 啟動 注意, 這篇隨筆的解說都放在最下面,會標 Explanation_XX,只要搜尋 Expl ...
- 网络爬虫——针对任意主题批量爬取PDF
|本文为博主原创,转载请说明出处 任务需求:要求通过Google针对任意关键字爬取大量PDF文档,如K-means,KNN,SVM等. 环境:Anaconda3--Windows7-64位--Pyth ...
- 小哈学Python第三课-字符集编码
table.hovertable { font-family: verdana, arial, sans-serif; font-size: 11px; color: #333333; border- ...
- Android - AIDL 使用
AIDL(Android Interface Definition Language) 程序员可以利用AIDL自定义编程接口,在客户端和服务端之间实现进程间通信(IPC).在Android平台上,一个 ...
- SLAM中的优化理论(一)—— 线性最小二乘
最近想写一篇系列博客比较系统的解释一下 SLAM 中运用到的优化理论相关内容,包括线性最小二乘.非线性最小二乘.最小二乘工具的使用.最大似然与最小二 乘的关系以及矩阵的稀疏性等内容.一方面是督促自己对 ...
- jacoco统计Android手工测试覆盖率并自动上报服务器
改进了几个点 1. 不用借助Instrumentation启动,正常启动即可: 2. 测试代码不用push到主分支,主分支代码拉到本地后用git apply patch方式合并覆盖率代码: 3. 测试 ...
- 提交到APPStore出现ERROR ITMS-90474
解决的方案是:在工程的targets--->General----->Develoment Info ------->Status BarStyle