JDBC处理器StatementHandler

简介: 回顾MyBatis的执行流程MyBatis是一个基于JDBC的Dao框架,但前面我们提到的会话、执行器完全没有提到JDBC,原因是MyBatis把所有跟JDBC相关的操作全部都放到了StatementHandler中。一个SQL请求会经过会话,然后是执行器,最由StatementHandler执行JDBC最终到达数据库。其关系如下图:注意:我们前面说过在一次会话中SqlSession、Executer、StatementHandler的比例是1:1:N(这里的N取决于通过会话调用了多少次Sql)。即使在可重用执行器的情况下这个比例也是成立的,因为我们只要执行一次SQL就会对应一个

回顾MyBatis的执行流程
MyBatis是一个基于JDBC的Dao框架,但前面我们提到的会话、执行器完全没有提到JDBC,原因是MyBatis把所有跟JDBC相关的操作全部都放到了StatementHandler中。

一个SQL请求会经过会话,然后是执行器,最由StatementHandler执行JDBC最终到达数据库。其关系如下图:

注意:我们前面说过在一次会话中SqlSession、Executer、StatementHandler的比例是1:1:N(这里的N取决于通过会话调用了多少次Sql)。即使在可重用执行器的情况下这个比例也是成立的,因为我们只要执行一次SQL就会对应一个StatementHandler。但是如果走了缓存就会影响,因为我们压根就不会走数据库操作!

StatementHandler定义与结构
StatementHandler定义:

JDBC处理器,基于JDBC构建JDBC Statement,并设置参数,然后执行Sql。每调用会话当中一次SQL,都会有与之相对应的且唯一的Statement实例。

StatementHandler结构

​ StatementHandler接口定义了JDBC操作的相关方法如下:

// 基于JDBC 声明Statement
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
// 为Statement 设置方法参数
void parameterize(Statement statement)
throws SQLException;
// 添加批处理(并非执行)
void batch(Statement statement)
throws SQLException;
// 执行update操作
int update(Statement statement)
throws SQLException;
// 执行query操作

List query(Statement statement, ResultHandler resultHandler)
throws SQLException;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
StatementHandler 有三个子类:

SimpleStatementHandler
PreparedStatementHandler
CallableStatementHandler
分别对应JDBC中的Statement、PreparedStatement、CallableStatement。

与三类执行器的频繁使用不同,这里的三种我们绝大多数情况下使用的都是PreparedStatementHandler。

PreparedStatement 有以下几个主要特点:

预编译 SQL 语句。PreparedStatement 对象代表一条预编译过的 SQL 语句。SQL 语句在被发送到数据库执行之前,先被编译。这样可以提高语句的执行效率。
实现参数设置。PreparedStatement 允许你通过 setXXX() 方法设置参数,然后执行这条 SQL 语句。这样可以防止 SQL 注入,提高安全性。
重复使用语句。PreparedStatement 可以安全地被重复执行。它会优化数据库资源,并有效地执行语句。
批量更新。PreparedStatement 支持通过 addBatch() 方法添加多条 SQL 命令,然后通过 executeBatch() 方法批量执行。这大大提高了更新/插入/删除记录的速度。
下面是一个 PreparedStatement 的示例:

String sql = "INSERT INTO EMP(ID, NAME) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);

pstmt.setInt(1, 101); // 为第一个参数设置 int 类型的值 101
pstmt.setString(2, "John"); // 为第二个参数设置 String 类型的值 "John"
pstmt.addBatch();

pstmt.setInt(1, 102);
pstmt.setString(2, "Tom");
pstmt.addBatch();

pstmt.executeBatch(); // 批量执行命令
1
2
3
4
5
6
7
8
9
10
11
12
这个示例中:

我们首先预编译一条 SQL 语句,这个语句使用了两个参数。
然后我们为这两个参数设置具体的值,添加到批处理中。
最后通过 executeBatch() 方法执行批处理,插入两条记录。
所以,总结来说,PreparedStatement 的主要特点有:

预编译 SQL 语句,提高执行效率。
实现参数设置,防止 SQL 注入。
可以安全重复执行,优化数据库资源。
支持批量更新,大大提高更新/插入/删除记录的速度。
PreparedStatement 是 JDBC 访问数据库的重要实现,它通过预编译和参数设置等特性,使得数据库访问更加高效和安全。

这三种StatementHandler有如下的共性:

添加批处理参数
设置返回的行数

所以这个时候我们会抽象出一个BaseStatementHandler来处理这些共性

PreparedStatementHandler执行流程

我们在上一篇文章中说过,查询数据的本质方法是doQuery(),他被query方法包了一层来处理缓存相关的业务。

查询数据库的执行过程分为三个阶段:

预处理:这里预处理不仅仅是通过Connection创建Statement,还包括设置参数。
SimpleExecuter类中:

执行:包含执行SQL获取结果集和处理结果映射(后面会说)两部分。

我们可以看到获取结果集后,使用ResultSetWrapper包装了一下。

关闭:直接关闭Statement。

参数处理和结果集封装,涉及数据库字段和JavaBean之间的相互映射,相对复杂。所以分别使用ParameterHandler与ResultSetHandler两个专门的组件实现。接下来就一起了解一下参数处理与结果集封装的处理流程。

在 MyBatis 中,PreparedStatementHandler 的执行流程如下:

调用 Connection.prepareStatement(sql) 创建一个 PreparedStatement 对象。sql 是映射文件中配置的 SQL 语句,可能包含参数 #{property}。
对SQL语句中的参数进行解析和值设置。
解析 #{property} 获得参数名称和参数值。参数值来源于传入的 Java 对象的属性值。
根据参数类型调用 PreparedStatement 的 setXxx() 方法设置参数值。如 setInt() 设置整数,setString() 设置字符串等。
调用 PreparedStatement 的 executeUpdate() 执行插入、更新、删除操作,或 executeQuery() 执行查询操作。
如果执行查询操作,还需要调用 ResultSetHandler 处理结果集。
DefaultResultSetHandler 会将 ResultSet 封装为 List 并返回。
BeanResultSetHandler 会将 ResultSet 封装为 JavaBean 对象并返回。
调用 PreparedStatement.close() 和 ResultSet.close() 释放资源。
参数处理
对应下面这一部分:

参数处理即将Java Bean转换成数据类型。总共要经历过三个步骤:

参数转换
参数映射
参数赋值
参数转换
在MyBatis中参数转换逻辑均在ParamNameResolver中实现

参数转换就是将JAVA 方法中的普通参数,封装转换成Map,以便map中的key和sql的参数引用相对应。

@Select({"select * from users where name=#{name} or age=#{user.age}"})
@Options
User selectByNameOrAge(@Param("name") String name, @Param("user") User user);
1
2
3
单个参数的情况下且没有设置@param注解会直接转换,忽略SQL中的引用名称。
多个参数情况:优先采用@Param中设置的名称,如果没有则用参数序号代替 即"param1、param2…"(作为key)
在JDK1.8之后支持直接通过反射获取变量名称作为key,前提javac编译时设置了 -parameters 编译参数,如果没有设置则转换成arg0,arg1
例如:

过程如下:

参数映射
映射是指Map中的key如何与SQL中绑定的参数相对应。以下这几种情况

单个原始类型:直接映射,勿略SQL中引用名称
Map类型:基于Map key映射
Object:基于属性名称映射,支持嵌套对象属性访问
在Object类型中,支持通过“.”方式映射属中的属性。如:user.age

@Select({"select * from users where name=#{name} or age=#{param2.age}"})
@Options
User selectByNameOrAge(@Param("name") String name, @Param("user") User user);
1
2
3
参数赋值
通过TypeHandler 为PrepareStatement设置值,通常情况下一般的数据类型MyBatis都有与之相对应的TypeHandler

结果集处理

指读取ResultSet数据,并将每一行转换成相对应的对象。用户可在转换的过程当中可以通过ResultContext来控制是否要继续转换。转换后的对象都会暂存在ResultHandler中最后统一封装成list返回给调用方

结果集转换中99%的逻辑DefaultResultSetHandler 中实现。整个流程可大致分为以下阶段:

读取结果集

遍历结果集当中的行

其本质就是调用resultSet.next()遍历行, 并且基于上下文判断是否要继续往下读取,这也就回应了我们前面所说的ResultContext的作用

暂存结果对象就是把我们解析好了的对象放在ResultHandler中

创建对象:有四种情况:

使用构造方法创建对象。MyBatis 会调用无参数的构造方法来创建 bean 实例。






1
2
3
4
5
使用工厂方法创建对象。MyBatis 会调用静态工厂方法来创建 bean 实例。








1
2
3
4
5
6
7
映射到既有的对象。MyBatis 会设置从结果集中获取的字段值到 bean 实例的属性上。





1
2
3
4
使用映射器接口实现映射。映射器接口是一个简单的接口,只包含获取和设置bean属性值的方法。MyBatis 会创建该接口的一个实现,并使用它来设置结果集的值。
public interface UserMapper {
void setId(Integer id);
void setUsername(String username);
}
1
2
3
4





1
2
3
4
填充属性

自动映射
手动映射:基于ResultMapping 获取属性的值
映射方面会在MyBatis映射体系一文中进行说明
————————————————
版权声明:本文为CSDN博主「十八岁讨厌编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zyb18507175502/article/details/130833169

目录
相关文章
|
5天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
1560 110
|
12天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1939 8
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
6天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
|
5天前
|
编解码 人工智能 安全
2核4G/4核8G/8核16G阿里云服务器如何选择实例?经济型e、通用算力型u2i与计算型c9i选哪个?
本文介绍了阿里云2核4G、4核8G、8核16G三档主流配置下经济型e、通用算力型u2i和计算型c9i三种实例的最新活动价格与适用场景。同配置下三者价差显著,以2核4G为例,经济型e低至599.93元/年,计算型c9i则高达1742.08元/年。文章详细解析了各实例的性能定位:经济型e适合轻负载入门场景,u2i兼顾稳定算力与性价比,c9i凭借第9代至强处理器与芯片级安全能力支撑高性能业务。同时提示用户可叠加满减优惠券享受折上折,建议根据业务负载与预算综合决策。
526 112
|
18天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
2530 4
|
10天前
|
存储 人工智能 关系型数据库
阿里云AI产品与云产品最新组合套餐:Token Plan、AI coding及云服务器和建站等组合优惠价
阿里云推出全新“算力+模型+应用”一站式云与AI组合套餐活动,覆盖从个人开发者到中大型企业的全场景需求。核心亮点为分三档定价的Token Plan订阅服务,支持Qwen3.8-Max-Preview大模型调用,错峰时段最低可享0.2折优惠。活动同步推出AI Coding、智能体部署、云电脑托管、0代码建站等十余类场景化组合,搭配99元/年的普惠云服务器、88元/年的入门数据库等经典特惠产品,还为企业提供1V1定制化AI转型方案,大幅降低了不同用户群体拥抱AI的技术门槛与采购成本。
719 111
|
20天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2632 13
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
6天前
|
人工智能 JSON Shell
2026AI漫剧本地全开源方案(附各个软件模型链接),8G显卡也能流畅运行
这是一套完全本地化部署的AI漫剧生成技术链路:涵盖LLM剧本分镜生成、FLUX文生图(IP-Adapter人脸锁定)、StoryDiffusion时序连贯控制、LTX-2.3唇形同步视频生成,及ComfyUI全流程调度。零云端费用,仅耗硬件算力,单集2–4小时可产出竖屏短视频,适配抖音/B站分发。
|
7天前
Qoder 一周年 × Qwen3.8-Max 正式上线,多重好礼限时领
8月3日,Qwen3.8-Max 正式上线Qoder,迎来Qoder一周年。新老用户可领800次免费调用,下单再赠2000次;夜间(22:00–08:00)调用5折;邀请好友双方得积分与调用额度。
438 1