Mybatis源码5 StatementHandler ,ParameterHandler
Mybatis5 StatementHandler ,ParameterHandler
一丶概述
前面我们总结了SqlSession--->CachingExecutor--->BaseExector---->Excutor子类 doQuery,doUpdate的执行流程,mybatis操作数据库总归是基于JDBC的,再和数据库打交道之前必定需要构建statement并且把参数映射到sql语句上,然后请求数据库,然后从Result中拿到数据映射到java 对象上。Excutor执行这些操作其实是调用下面三大对象完成的:
- StatementHandler:作用是使用数据库的Statement(默认使用PreparedStatement)执行操作,它是四大对象的核心,起到承上启下的作用,许多重要的插件都是通过拦截它来实现的。
- ParameterHandler:是用来处理SQL参数的。
- ResultSetHandler:是进行数据集(ResultSet)的封装返回处理的
执行的流程如下
二丶Excutor是如何得到应该使用的StamentHandler的
1.Exectuor准备StatmentHandler并且调用的逻辑
- SimpleExecutor
当真正需要请求数据库时,从Configuration大管家中创造一个新的StatementHandler(ReuseExecutor 使用了Map缓存sql和对应的StatmentHanler 并不一定会去new 一个StatementHandler)
接着准备调用prepareStatement
主要是获取连接(这个获取的连接被mybatis进行了动态代理,提供了打印日志的功能)然后调用StamentHandler的prepare方法创建一个Statment并且调用StamentHandler的parameterize 将参数映射到sql中,后面就是执行器调用Statment的 query or update 方法操作数据
ReuseExecutor
大体逻辑和SimpleExector相同,准备Statment 的逻辑不一样
从缓存map中根据sql 拿Statment 这是ReuseExecutor 为什么叫 ReuseExecutor的原因,但是不是拿到Statment即可,还要确保statement的数据库连接没有关闭了(这里个人觉得有点瑕疵,既然数据库连接关闭了,而且这个map中的Statement也不会被继续使用了,为什么不将这个Statement也关闭)
BatchExecutor
对应StatmentHandler的操作和SimpleExecutor一样,只是BatchExecutor的doUpdate方法会调用StatmentHandler的batch方法,而且会使用list存储每一个Statement和对应的BachResult,调用doFlushStatements会进行批量提交
三丶StatementHandler和Configuration创建StatementHandler
1.StatemenHanlder接口
定义了StatementHandler的基本功能
//准备语句 子类可以实现返回不同的Statement子类
Statement prepare(Connection connection)
throws SQLException;
//参数化
void parameterize(Statement statement)
throws SQLException;
//批处理
void batch(Statement statement)
throws SQLException;
//update
int update(Statement statement)
throws SQLException;
//select-->结果给ResultHandler
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
//得到绑定sql
BoundSql getBoundSql();
//得到参数处理器
ParameterHandler getParameterHandler();
2.BaseStatementHandler
模板方法设计模式,提取公共的操作到父类,具体不同的地方抽成抽象方法交由子类实现
prepare
设置超时时长 setStatementTimeout
优先选择mapperstatement中的超时时长(对xml TimeOut指定的内容)后选择Configuration中指定的超时时长,根本是调用 stmt.setQueryTimeout
设置读取条数 setFetchSize
获取mappedStatement中设置的FetchSize设置(起始我们如果数据库数据过多可以设置最多获取多少条,避免oom)根本是调用stmt.setFetchSize
3.RoutingStatementHandler
主要是适配多个StatmentHandler的实现,有点装饰器,有点工厂,又有点适配器的意思
后续具体方法的实现都是调用delegate对应的方法,相当于RoutingStatementHandler 只是做了一个根据MappedStatement中的StatementType配置创建不同的StatmentHandler
4.PrepareStatementHandler
默认的StatementHandler
- instantiateStatement
为什么新增更新删除可以返回影响的行数
本质是调用了PreparedStatement.getUpdateCount 返回
parameterize 调用parameterHandler 进行参数映射
query调用 resultSetHandler的handleResultSets进行参数映射
5.SimpleStatementHandler
- instantiateStatement
connection.createStatement生成Statement
6.CallableStatementHandler
instantiateStatement
connection.prepareCall 生成Statement
update 和 query方法会调用resultSetHandler 处理存储过程的输出参数
parameterize相比PrepareStatementHandler多了将存储过程的输出参数注册到 CallableStatement
7.Configuration创建StatementHandler
默认创建的是RoutingStatementHandler 或许我们可以把 RoutingStatementHandler 构造方法内,根据StatementType船舰不同实现的逻辑移到这里也是一样的
interceptorChain.pluginAll 使用责任链和动态代理对每一个StatementHandler进行动态代理
四丶ParameterHandler
- ParameterHandler接口定义了如何获取参数,和如何如何设置参数的两个方法
- DefaultParameterHandler 是ParameterHandler接口的唯一实现
1.DefaultParameterHandler 是如何设置参数的
//设置参数
@Override
public void setParameters(PreparedStatement ps) throws SQLException {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
//1.获取sql语句的参数,ParameterMapping里面包含参数的名称类型等详细信息,还包括类型处理器
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
//2.遍历依次处理
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
//3.OUT类型参数不处理
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
//4.获取参数名称
String propertyName = parameterMapping.getProperty();
//5.如果propertyName是动态参数,就会从动态参数中取值。(当使用<foreach>的时候,MyBatis会自动生成额外的动态参数)
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
//6.如果参数是null,不管属性名是什么,都会返回null。
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
//7.判断类型处理器是否有参数类型,如果参数是一个简单类型,或者是一个注册了typeHandler的对象类型,就会直接使用该参数作为返回值,和属性名无关。
value = parameterObject;
} else {
//8.这种情况下是复杂对象或者Map类型,通过反射方便的取值。通过MetaObject操作
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
//9.获取对应的数据库类型
JdbcType jdbcType = parameterMapping.getJdbcType();
//空类型
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
//10.对PreparedStatement的占位符设置值(类型处理器可以给PreparedStatement设值)
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
Mybatis源码5 StatementHandler ,ParameterHandler的更多相关文章
- Mybatis源码分析-StatementHandler
承接前文Mybatis源码分析-BaseExecutor,本文则对通过StatementHandler接口完成数据库的CRUD操作作简单的分析 StatementHandler#接口列表 //获取St ...
- mybatis源码之StatementHandler
/** * @author Clinton Begin */ public interface StatementHandler { Statement prepare(Connection conn ...
- 精尽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 源码分析 - 插件机制
1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...
- MyBatis 源码分析 - SQL 的执行过程
* 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析 ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- Mybatis源码分析
MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...
- Mybatis源码正确打开方式
精心挑选要阅读的源码项目: 饮水思源——官方文档,先看文档再看源码: 下载源码,安装到本地,保证能编译运行: 从宏观到微观,从整体到细节: 找到入口,抓主放次,梳理核心流程: 源码调试,找到核心数据结 ...
随机推荐
- Python中的可迭代对象和迭代器
1.可迭代对象 1.1.可迭代对象概念 可迭代对象,最直观的感觉就是可以使用for来循环迭代每一个元素.例如Python内置的类型:str.list.tuple.dict等类型的对象,都是可迭代对象. ...
- 软件开发人员 Kubernetes 入门指南|Part 1
Kubernetes 是一个用于部署和管理容器的编排系统.使用 Kubernetes,用户可以通过自动执行管理任务(例如在跨节点间扩展容器并在容器停止时重新启动任务),在不同环境中可靠地运行容器. K ...
- 挑战程序设计竞赛 2.2 poj 3040 Allowance 贪心
https://vjudge.csgrandeur.cn/problem/POJ-3040 /* 作为创纪录的牛奶产量的奖励,约翰决定每周给贝西一小笔零用钱.FJ拥有一组N(1 <= N < ...
- k8s-单节点升级为集群(高可用)
单master节点升级为高可用集群 对于生产环境来说,单节点master风险太大了. 非常有必要做一个高可用的集群,这里的高可用主要是针对控制面板来说的,比如 kube-apiserver.etcd. ...
- P5445 [APIO2019] 路灯 题解
题目链接 题目描述 给你一个 01 串,有 \(q\) 个时刻,每个时刻要么把一位取反,要么问你在过去的所有时刻中有多少个时刻 \(a\) 和 \(b-1\) 之间都为 1. 题目分析 观察题目,我们 ...
- 关于PaddleOCR识别时中文路径导致报错/没输出结果
此处只做学习PaddleOCR时遇到的一些坑 一.Python版本与PaddleOCR兼容性问题 如果你在Python11的环境下安装PaddlePaddle,使用 paddleocr --image ...
- 使用visualvm远程监控JVM
参考:http://blog.sina.com.cn/s/blog_4e90b3ba0100muco.html 1.首先要修改JDK中JMX服务的配置文件,以获得相应的权限: 在jdk-1.6.0_2 ...
- OpenGL 着色器详解
1. GLSL语言 glsl语言是用来编写着色器的,通过一段一段包含main函数的程序片段,告诉渲染引擎怎么去渲染内容. glsl语言的语法有点类似c语言风格,只是增加了一些特有的关键字来修饰变量,下 ...
- SQL改写案例4(开窗函数取中位数案例)
周总找我问个报表SQL实现逻辑的案例,废话不说给他看看. 原SQL: SELECT d.tname 姓名, d.spname 岗位, d.sum_cnt 报单单量, d.min_cnt 放款单量, d ...
- SNN_LIF模型
LIF模型 Leaky integrity-Fire(LIF)模型 输入信号直接影响神经元的状态,即神经元膜电位,只有当膜电位上升到阈值的时候,才会产生输出信号. 膜电位:细胞膜两侧的电位差.只有当膜 ...