mybatis核心配置_MyBatis 核心配置综述之StatementHandler
StatementHandler 是四大组件中最重要的一个对象,负责操作 Statement 对象与数据库进行交流,在工作时还会使用 ParameterHandler 和 ResultSetHandler 对参数进行映射,对结果进行实体类的绑定
MyBatis 四大组件之StatementHandler
我们在搭建原生JDBC的时候,会有这样一行代码
Statement stmt = conn.createStatement(); //也可以使用PreparedStatement来做
这行代码创建的 Statement 对象或者是 PreparedStatement 对象就是由StatementHandler进行管理的。
StatementHandler 的基本构成
来看一下StatementHandler中的主要方法:
- prepare: 用于创建一个具体的 Statement 对象的实现类或者是 Statement 对象
- parametersize: 用于初始化 Statement 对象以及对sql的占位符进行赋值
- update: 用于通知 Statement 对象将 insert、update、delete 操作推送到数据库
- query: 用于通知 Statement 对象将 select 操作推送数据库并返回对应的查询结果
StatementHandler的继承结构
有没有感觉和 Executor 的继承体系很相似呢?最顶级接口是四大组件对象,分别有两个实现类 BaseStatementHandler 和 RoutingStatementHandler ,BaseStatementHandler 有三个实现类, 他们分别是 SimpleStatementHandler、PreparedStatementHandler 和 CallableStatementHandler。
RoutingStatementHandler: RoutingStatementHandler 并没有对 Statement 对象进行使用,只是根据StatementType 来创建一个代理,代理的就是对应Handler的三种实现类。在MyBatis工作时,使用的StatementHandler 接口对象实际上就是 RoutingStatementHandler 对象。我们可以理解为
StatementHandler statmentHandler = new RountingStatementHandler();
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// 根据 statementType 创建对应的 Statement 对象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());}
}
BaseStatementHandler: 是 StatementHandler 接口的另一个实现类.本身是一个抽象类.用于简化StatementHandler 接口实现的难度,属于适配器设计模式体现,它主要有三个实现类
- SimpleStatementHandler: 管理 Statement 对象并向数据库中推送不需要预编译的SQL语句
- PreparedStatementHandler: 管理 Statement 对象并向数据中推送需要预编译的SQL语句,
- CallableStatementHandler:管理 Statement 对象并调用数据库中的存储过程
StatementHandler 对象创建以及源码分析
StatementHandler 对象是在 SqlSession 对象接收到命令操作时,由 Configuration 对象中的newStatementHandler 负责调用的,也就是说 Configuration 中的 newStatementHandler 是由执行器中的查询、更新(插入、更新、删除)方法来提供的,StatementHandler 其实就是由 Executor 负责管理和创建的。
SimpleExecutor.java
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {// 获取环境配置Configuration configuration = ms.getConfiguration();// 创建StatementHandler,解析SQL语句StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = prepareStatement(handler, ms.getStatementLog());// 由handler来对SQL语句执行解析工作return handler.<E>query(stmt, resultHandler);} finally {closeStatement(stmt);}}
由图中可以看出,StatementHandler 默认创建一个 RoutingStatementHandler ,这也就是 StatementHandler 的默认实现,由 RoutingStatementHandler 负责根据 StatementType 创建对应的StatementHandler 来处理调用。
prepare方法调用流程分析
prepare 方法的调用过程是这样的,在上面的源码分析过程中,我们分析到了执行器 Executor 在执行SQL语句的时候会创建 StatementHandler 对象,进而经过一系列的 StatementHandler 类型的判断并初始化。再拿到StatementHandler 返回的 statementhandler 对象的时候,会调用其prepareStatement() 方法,下面就来一起看一下 preparedStatement() 方法(我们以简单执行器为例,因为创建其 StatementHandler 对象的流程和执行 preparedStatement() 方法的流程是差不多的):
SimpleExecutor.java
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {Statement stmt = null;try {// 获取环境配置Configuration configuration = ms.getConfiguration();// 创建StatementHandler,解析SQL语句StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);stmt = prepareStatement(handler, ms.getStatementLog());// 由handler来对SQL语句执行解析工作return handler.<E>query(stmt, resultHandler);} finally {closeStatement(stmt);}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {Statement stmt;Connection connection = getConnection(statementLog);stmt = handler.prepare(connection, transaction.getTimeout());handler.parameterize(stmt);return stmt;
}
// prepare方法调用到 StatementHandler 的实现类RoutingStatementHandler,再由RoutingStatementHandler调用BaseStatementHandler中的prepare 方法
// RoutingStatementHandler.java
@Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {return delegate.prepare(connection, transactionTimeout);}
// BaseStatementHandler.java@Overridepublic Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {ErrorContext.instance().sql(boundSql.getSql());Statement statement = null;try {statement = instantiateStatement(connection);setStatementTimeout(statement, transactionTimeout);setFetchSize(statement);return statement;} ...
其中最重要的方法就是 instantiateStatement() 方法了,在得到数据库连接 connection 的对象的时候,会去调用 instantiateStatement() 方法,instantiateStatement 方法位于 StatementHandler 中,是一个抽象方法由子类去实现,实际执行的是三种 StatementHandler 中的一种,我们还以 SimpleStatementHandler 为例
protected Statement instantiateStatement(Connection connection) throws SQLException {if (mappedStatement.getResultSetType() != null) {return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);} else {return connection.createStatement();}}
从上面代码我们可以看到,instantiateStatement() 最终返回的也是Statement对象,经过一系列的调用会把statement 对象返回到 SimpleExecutor 简单执行器中,为 parametersize 方法所用。也就是说,prepare 方法负责生成 Statement 实例对象,而 parameterize 方法用于处理 Statement 实例多对应的参数。
parametersize 方法调用流程分析
parametersize 方法看的就比较畅快了,也是经由执行器来管理 parametersize 的方法调用,这次我们还想以SimpleStatementHandler 为例但是却不行了?为什么呢?因为 SimpleStatementHandler 是个空实现了,为什么是null呢?因为 SimpleStatementHandler 只负责处理简单SQL,能够直接查询得到结果的SQL,例如:
select studenname from Student
而 SimpleStatementHandler 又不涉及到参数的赋值问题,那么参数赋值该在哪里进行呢?实际上为参数赋值这步操作是在 PreparedStatementHandler 中进行的,因此我们的主要关注点在 PreparedStatementHandler 中的parameterize 方法
public void parameterize(Statement statement) throws SQLException {parameterHandler.setParameters((PreparedStatement) statement);
}
我们可以看到,为参数赋值的工作是由一个叫做 parameterHandler 对象完成的,都是这样的吗?来看一下CallableStatementHandler
public void parameterize(Statement statement) throws SQLException {registerOutputParameters((CallableStatement) statement);parameterHandler.setParameters((CallableStatement) statement);
}
上面代码可以看到,CallableStatementHandler 也是由 parameterHandler 进行参数赋值的。
那么这个 parameterHandler 到底是什么呢?这个问题能想到说明老兄你已经上道了,这也就是我们执行器的第三个组件。这个组件我们在下一节进行分析
update 方法调用流程分析
用一幅流程图来表示一下这个调用过程:
简单描述一下update 方法的执行过程:
- MyBatis 接收到 update 请求后会先找到 CachingExecutor 缓存执行器查询是否需要刷新缓存,然后找到BaseExecutor 执行 update 方法;
- BaseExecutor 基础执行器会清空一级缓存,然后交给再根据执行器的类型找到对应的执行器,继续执行 update 方法;
- 具体的执行器会先创建 Configuration 对象,根据 Configuration 对象调用 newStatementHandler 方法,返回 statementHandler 的句柄;
- 具体的执行器会调用 prepareStatement 方法,找到本类的 prepareStatement 方法后,再有prepareStatement 方法调用 StatementHandler 的子类 BaseStatementHandler 中的 prepare 方法
- BaseStatementHandler 中的 prepare 方法会调用 instantiateStatement 实例化具体的 Statement 对象并返回给具体的执行器对象
- 由具体的执行器对象调用 parameterize 方法给参数进行赋值。
续上上面的 parameter方法,具体交给 ParameterHandler 进行进一步的赋值处理
Query 查询方法几乎和 update 方法相同,这里就不再详细的举例说明了.
原文:主页 - 头条号
来源:今日头条
作者:Java架构师CAT
mybatis核心配置_MyBatis 核心配置综述之StatementHandler相关推荐
- 未设置服务器核心文件,[问题3] dhcpd.conf是DHCP服务器的配置的核心,每次启动DH..._考试资料网...
问答题在一个基于TCP/IP协议的网络中,每台主机都有会有一个IP地址(如:Internet).Inter- net上的每台主机都有一个惟一的IP地址,根据获得IP址的方式不同,可以分为静态IP,动态 ...
- hibernate教程--常用配置和核心API详解
一.Hibernate的常用的配置及核心API. 1.1 Hibernate的常见配置: 1.1.1.核心配置: 核心配置有两种方式进行配置: 1)属性文件的配置: * hibernate.prop ...
- hibernate教程--常用配置和核心API
一.Hibernate的常用的配置及核心API. 1.1Hibernate的常见配置: 1.1.1.核心配置: 核心配置有两种方式进行配置: 1)属性文件的配置: * hibernate.proper ...
- SpringBoot核心原理:自动配置、事件驱动、Condition
点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/l6108003/article/ details/106966386 前言 SpringBoot是Spring的包装,通过自动 ...
- 部门WIFI配置-防火墙-核心交换机和POE交换机
最近做的一个比较简单的wifi的配置,负责的是一台防火墙,一台核心交换机,一台poe交换机.AC和AP都不是我们负责. 先说一下防火墙的配置: 常规的开局就不说了 防火墙的G1/0/0 与运营商相连, ...
- 更换公司核心路由器案例配置---1.console初始配置-2.用户配置-3.telnet登录配置-4.NAT端口映射配置-5.内网服务器配置-6.链路聚合配置-7.DHCP和DNS配置
一.场景 因公司核心路由器老旧,运行不稳定,对旧路由器进行更换,要在路由器上实现以下功能. 1.模拟新机console初始配置: 2.用户配置: 3.模拟通过telne ...
- mybatis 遍历数组_Mybatis中别名、插件与数据源配置
上一篇介绍了Configuration的properties和settings,接下来继续. 设置别名 别名也是mybatis中最重要的配置之一,可以通过很简单的一个字符串来代替一个Class,它可以 ...
- java web核心编程_JavaWeb核心编程之(三)Servlet配置
Servlet配置 1.配置Serlvet加载时机 2.配置多映射 配置加载时机 新建项目config->创建包com.xiaoan.config->创建类FirstServlet imp ...
- 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)
上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, ...
最新文章
- debian php mysql 包_Linux+Varnish+Apache+MySQL+PHP一键包For Ubuntu/Debian
- Microsoft Dynamics CRM4.0 Data Auditing and Restore (数据审核和恢复)
- ISA 2006 允许使用QQ
- dell 远程访问管理卡iDRAC 7
- wpf开发仿真3d软件_web 3d 与仿真
- SpringBoot聚合项目总结
- win10 安装mysql-5.7.19-winx64
- oracle关键字 bulk,oracle和sqlserver的一些保留关键字
- Eclipse/MyEclipse注释模板和格式化模板的使用
- Linux下高速缓存DNS的配置
- Java模拟实现一个基于文本界面的《家庭记账软件》
- 多线程-Thread.join()的运用
- springboot-jpa-querydsl
- 数据库和数据库管理系统的区别
- GDOI2017小结
- 软件测试判定表测试用例,黑盒测试用例设计方法之判定表法
- 调查显示:SD-WAN部署迅猛增长,MPLS不会消失
- deepstream运行TAO模型
- 几何光学学习笔记(12)- 3.9几种典型系统的理想光学系统性质 3.10 矩阵运算在几何光学中的应用
- 区分event对象中的[clientX,offsetX,screenX,pageX]
热门文章
- python逐行读取数据时出现错误_Python利用逐行读取readline()打印出现空行的解决办法...
- 数据自治开放应用平台设计与实践
- 作者:Anjaneyulu Passala, 男,印度理工学院计算机科学与工程学院博士,印孚瑟斯技术有限公司主任研究科学家。...
- 客座编辑:杜小勇(1963‒),中国人民大学信息学院教授,博士生导师。
- 【JSP】web.xml配置JavaWeb项目首页
- 需求分析——掌握UML建模语言的用例图
- Python3 标准库及相关内容
- vue组件之间8种组件通信方式总结
- MySQL数据库----触发器
- 解决HP ProLiant DL380 G5的Centos 7安装与启动不能识别硬盘问题