Mybatis执行器(Executor)

Executor简介

Executor

Executor是MyBatis的核心接口之一,其中定义了数据库操作的基本方法。在实际应用中经常涉及的SqlSession接口的功能,都是基于Executor接口实现的。

BaseExecutor

BaseExecutor是一个实现了Executor接口的抽象类,它实现了Executor 接口的大部分方法。BaseExecutor 中主要提供了缓存管理和事务管理的基本功能。继承BaseExecutor 的子类只要实现四个基本方法来完成数据库的相关操作即可,这四个方法是:doUpdate()方法、doQuery()方法、doQueryCursor()方法、doFlushstatement()方法, 其余的功能在BaseExecutor中实现。

SimpleExecutor

SimpleExecutor 继承了BaseExecutor 抽象类,它是最简单的 Executor 接口实现。Executor使用了模板方法模式,一级缓存等固定不变的操作都封装到了BaseExecutor中,SimpleExecutor中就不必再关心一级缓存等操作,只需要专注实现4个基本方法的实现即可。

ReuseExecutor

在传统的JDBC编程中,重用Statement对象是常用的一种优化手段,该优化手段可以减少SQL预编译的开销以及创建和销毁 Statement 对象的开销,从而提高性能。
ReuseExecutor提供了Statement重用的功能,ReuseExecutor 中通过statementMap字段(HashMap<String, Statement>类型)缓存使用过的 Statement 对象,key是SQL 语句,value是SQL对应的Statement对象。
ReuseExecutor.doQuery()、doQueryCursor()、doUpdate()方法的实现与SimpleExecutor 中对应方法的实现一样,区别在于其中调用的 prepareStatement()方法,SimpleExecutor 每次都会通过JDBC Connection创建新的Statement对象,而ReuseExecutor则会先尝试重用StatementMap中缓存的Statement对象。

BatchExecutor

应用系统在执行一条SQL语句时,会将SQL语句以及相关参数通过网络发送到数据库系统。对于频繁操作数据库的应用系统来说,如果执行一条SQL语句就向数据库发送一次请求,很多时间会浪费在网络通信上。使用批量处理的优化方式可以在客户端缓存多条SQL语句,并在合适的时机将多条SQL语句打包发送给数据库执行,从而减少网络方面的开销,提升系统的性能。
不过有一点需要注意,在批量执行多条SQL语句时,每次向数据库发送的SQL语句条数是有上限的,如果超过这个上限,数据库会拒绝执行这些SQL语句并抛出异常。所以批量发送SQL语句的时机很重要。

执行器功能演示

代码准备

创建配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties><property name="driver" value="com.mysql.cj.jdbc.Driver" /><property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true" /><property name="username" value="root" /><property name="password" value="123456" /></properties><settings><setting name="mapUnderscoreToCamelCase" value="true"/></settings><environments default="default"><environment id="default"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}" /><property name="url" value="${url}" /><property name="username" value="${username}" /><property name="password" value="${password}" /></dataSource></environment></environments><mappers><mapper resource="mapper/EmployeeMapper.xml" /></mappers></configuration>
创建实体类EmployeeDO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmployeeDO {private Integer id;private String name;private Integer age;private String phone;
}
创建EmployeeMapper接口
public interface EmployeeMapper {EmployeeDO getEmployeeById(Integer id);int addEmployee(EmployeeDO employeeDO);
}
创建EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ys.mybatis.mapper.EmployeeMapper"><select id="getEmployeeById" resultType="com.ys.mybatis.DO.EmployeeDO">select * from employee where id = #{id}</select><insert id="addEmployee" useGeneratedKeys="true" keyProperty="id">insert into employee(`name`, `age`, `phone`) VALUES (#{name},#{age},#{phone})</insert></mapper>
创建测试类EmployeeTest
@Slf4j
public class EmployeeTest1 {private SqlSessionFactory sqlSessionFactory;private Configuration configuration;@BeforeEachpublic void before() {InputStream inputStream = ConfigurationTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);configuration = sqlSessionFactory.getConfiguration();}@Testpublic void queryForSimpleExecutor() {SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);EmployeeDO firstQuery = employeeMapper.getEmployeeById(1);EmployeeDO secondQuery = employeeMapper.getEmployeeById(2);System.out.println(firstQuery);System.out.println(secondQuery);}@Testpublic void queryForReuseExecutor() {SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE);EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);EmployeeDO firstQuery = employeeMapper.getEmployeeById(1);EmployeeDO secondQuery = employeeMapper.getEmployeeById(2);System.out.println(firstQuery);System.out.println(secondQuery);}@Testpublic void batchProcessingForSimpleExecutor() {Random random = new Random();SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE);EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);long start = System.currentTimeMillis();for (int i = 0; i < 1000; i++) {EmployeeDO employee = new EmployeeDO(null, getRandomName(), random.nextInt(100), getRandomPhone());employeeMapper.addEmployee(employee);}sqlSession.commit();long end = System.currentTimeMillis();System.out.println("共耗时:" + (end - start) / 1000);}@Testpublic void batchProcessingForReuseExecutor() {Random random = new Random();SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.REUSE);EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);long start = System.currentTimeMillis();for (int i = 0; i < 1000; i++) {EmployeeDO employee = new EmployeeDO(null, getRandomName(), random.nextInt(100), getRandomPhone());employeeMapper.addEmployee(employee);}sqlSession.commit();long end = System.currentTimeMillis();System.out.println("共耗时:" + (end - start) / 1000);}@Testpublic void batchProcessingForBatchExecutor() {boolean autoCommit = false;Environment environment = configuration.getEnvironment();Transaction transaction = environment.getTransactionFactory().newTransaction(environment.getDataSource(), TransactionIsolationLevel.REPEATABLE_READ, autoCommit);BatchExecutor batchExecutor = new BatchExecutor(configuration, transaction);Random random = new Random();try (DefaultSqlSession sqlSession = new DefaultSqlSession(configuration, batchExecutor, autoCommit)) {EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);long start = System.currentTimeMillis();for (int i = 0; i < 1000; i++) {EmployeeDO employee = new EmployeeDO(null, getRandomName(), random.nextInt(100), getRandomPhone());employeeMapper.addEmployee(employee);}sqlSession.commit();long end = System.currentTimeMillis();System.out.println("共耗时:" + (end - start) / 1000);}}private String getRandomName() {return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 5);}private String getRandomPhone() {StringBuilder sb = new StringBuilder("1");Random random = new Random();IntStream.range(0, 10).forEach(i -> sb.append(random.nextInt(10)));return sb.toString();}}

查询 : SimpleExecutor vs ReuseExecutor

执行queryForSimpleExecutor

每执行一次查询,预编译一次

执行queryForReuseExecutor

多次查询,只预编译一次

批量插入 : SimpleExecutor vs ReuseExecutor vs BatchExecutor

执行batchProcessingForSimpleExecutor

插入1000条数据耗时 : 55s

执行batchProcessingForReuseExecutor

插入1000条数据耗时 : 47s

执行batchProcessingForBatchExecutor

插入1000条数据耗时 : 21s

原因简析
  • ReuseExecutor  vs SimpleExecutor : 减少了预编译次数
  • BatchExecutor vs ReuseExecutor  : 减少了与数据库交互次数

PS : ReuseExecutor和SimpleExecutor在执行批量插入的时候其实性能差距不太大,要是执行ReuseExecutor的批量插入时刚好机器负载大,执行SimpleExecutor的批量插入时机器负载小,有可能出现SimpleExecutor的批量插入用时更少的情况

源码简析

SimpleExecutor.doQuery() vs ReuseExecutor.doQuery()

SimpleExecutor的doQuery()方法和ReuseExecutor的doQuery()方法基本上是一致的,主要差异就是prepareStatement这个方法的内部实现。SimpleExecutor每次都重新编译Statement,而ReuseExecutor则是将Statement缓存起来,以供下次查询使用

SimpleExecutor.doQuery() vs BatchExecutor.doQuery()

如果仅执行查询操作,SimpleExecutor的doQuery()方法和BatchExecutor的doQuery()方法的效果是一样的,只是BatchExecutor的doQuery()方法会多一个批量刷新的方法。BatchExecutor执行器执行插入或者更新操作的时候不会立即执行,而是封装成BatchResult对象,等执行flushStatements方法的时候才是真正执行相关操作。即BatchExecutor在执行更新操作中间执行了查询操作也会触发批处理,如果更新操作中间没有查询操作,那只有等到执行sqlSession的commit方法才会执行flushStatements

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/800614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pytorch 与 python版本对应关系

pytorch 与 python版本对应关系 torchtorchvisionPythonmain / nightlymain / nightly>3.8, <3.112.20.17>3.8, <3.112.10.16>3.8, <3.112.00.15>3.8, <3.111.130.14>3.7.2, <3.101.120.13>3.7, <3.101.110.12>3.7, <3.101.100.11&…

word文档拆分

Word如何拆分文档&#xff1f;-Word将文档拆分的方法 - 极光下载站 (xz7.com) 可以参考这篇&#xff0c;注意需要全部选中后再创建。 最需要注意的是&#xff0c;拆分后原文档不存在了&#xff0c;最多可以显示引用的拆分的文档&#xff0c;如果拆分有误&#xff0c;则无法恢复…

Yolov8-pose关键点检测:特征融合 | CAMixing:卷积-注意融合模块和多尺度提取能力 | 2024年4月最新成果

💡💡💡本文独家改进:CAMixingBlock更好的提取全局上下文信息和局部特征,包括两个部分:卷积-注意融合模块和多尺度前馈网络; 💡💡💡如何跟YOLOv8结合:1)放在backbone后增强对全局和局部特征的提取能力;2)放在detect前面,增强detect提取能力; 提供多种改进方…

RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs

RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs 文章目录 RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs1. 修改用户的密码1. 修改密码语法2. 修改案例 2.修改角色tags1. 修改标签(tags)语法2. 修改案例 可以使用 RabbitMQ 的命令行工具 rabbitmqctl 来修改用…

【MATLAB源码-第180期】基于matlab的PTS,SLM,CPFilter三种降低OFDM系统的PAPR仿真。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 限幅和滤波&#xff08;Clipping and Filtering&#xff09; 原理简介 限幅和滤波是一种基础且直观的方法&#xff0c;用于降低OFDM信号的PAPR。在限幅阶段&#xff0c;信号的幅度在达到设定阈值时会被削减&#xff0c;…

皮具5G智能制造工厂数字孪生可视化平台,推进企业数字化转型

皮具5G智能制造工厂数字孪生可视化平台&#xff0c;推进企业数字化转型。随着信息技术的快速发展&#xff0c;数字化转型已成为企业提升竞争力、实现可持续发展的关键路径。皮具行业&#xff0c;作为一个传统的手工制造业&#xff0c;正面临着巨大的市场变革和技术挑战。如何在…

红队打靶:holynix打靶流程-文件包含-文件上传-修改伪设备提权(vulnhub)

目录 开头 1.主机发现和端口扫描 2.80端口-万能密码-文件泄露 sql注入万能密码 文件泄露-读取/etc/passwd文件 sqlmap POST注入| SQL注入实现越权 | 水平越权 最后构造的sql语句,为什么这么构造嘞&#xff1f; 3.文件上传、文件解析漏洞利用 浏览器怎么访问家目录啊&…

你不知道的10个光伏冷知识!

对于光伏发电许多人都不是很了解&#xff0c;今天小编整理了10个光伏方面的冷知识分享。 1.光伏是如何诞生的&#xff1f; 1839年&#xff0c;19岁的法国贝克勒尔做物理实验时&#xff0c;发现在导电液中的两种金属电极用光照射时电流会加强&#xff0c;从而发现了“光生伏打…

C语言指针—指针和指针类型

指针是什么&#xff1f; 指针是什么&#xff1f; 指针理解的2个要点&#xff1a; 指针是内存中一个最小单元的编号&#xff0c;也就是地址 平时口语中说的指针&#xff0c;通常指的是指针变量&#xff0c;是用来存放内存地址的变量 总结&#xff1a;指针就是地址&#xff0c;口…

Flutter 单例模式的多种实现方法与使用场景分析

单例模式是一种常用的设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点。在Flutter应用程序中&#xff0c;单例模式可以有效地管理全局状态、资源共享和对象的生命周期。本文将介绍Flutter中实现单例模式的多种方法&#xff0c;并分析它们的使…

【leetcode面试经典150题】19.最后一个单词的长度(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

loopvar 改动不同版本的影响-defer,closures

defer示例代码 package mainimport ("fmt""runtime" )func main() {fmt.Println("golang version:", runtime.Version())defer_demo() }func defer_demo() {defer println()for counter, n : 0, 0; n < 3; n {defer func(v int) {fmt.Print(…

Windows深度学习环境----Cuda version 10.2 pytorch3d version 0.3.0

Requirements Python version 3.8.5Pytorch version: pytorch1.6.0 torchvision0.8.2 torchaudio0.7.0 cudatoolkit10.2.89pytorch3d version 0.3.0Cuda version 10.2 感觉readme文件里的不适配&#xff0c;跟pytorch官网不同 以前的 PyTorch 版本 |PyTorch的 # CUDA 10.2 c…

2024-04-08 问AI: 介绍一下AI 大神 吴恩达

文心一言 吴恩达&#xff08;Andrew Ng&#xff09;是AI领域的一位重要人物&#xff0c;他的贡献和影响力在学术界、工业界以及在线教育领域都极为显著。 吴恩达出生于1976年&#xff0c;是一位华裔美国人&#xff0c;他在斯坦福大学担任计算机科学系和电子工程系的副教授&am…

充电桩项目,开源啦!

好&#xff0c;我是田哥 很多人&#xff0c;最近都在关注我的充电桩项目&#xff0c;之前建了一个微服务架构的项目&#xff0c;也有单体项目的代码开源。 今天&#xff0c;我把最新版微服务架构的充电桩项目源代码开源。 充电桩的输入端与交流电网直接连接&#xff0c;输出端都…

WindowServer2019远程桌面无法连接问题及处理方法

WindowServer2019远程桌面无法连接问题及处理方法 文章目录 WindowServer2019远程桌面无法连接问题及处理方法1. 问题描述1. 连接问题2. 原因分析 2. 解决方法1. 零时解决方法2. 永久解决方法1. 打开注册表编辑器2. GracePeriod的权限权限设置3. 删除REG_BINARY4. 重启 1. 问题…

VMware配置环境(安装运行问题)及系列dns端口网络类型IP远程连接学习之(详谈8000字)

安装vmware快速配置步骤 下载VMware安装包 在下载好VMware安装包之后双击运行 接受条款 关闭VMware自动更新 勾选快捷键方式 安装VMware安装 输入许可证&#xff08;有需要私信小编&#xff09; 安装完成 重启电脑即可 最终成功界面: 安装Linux系统 创建虚拟机 选择…

【代码随想录】【贪心算法】day36:无重叠子区间,划分字母区间,合并区间

class Solution(object):def eraseOverlapIntervals(self, intervals):""":type intervals: List[List[int]]:rtype: int"""intervals.sort(keylambda x:x[0])count0# 可以记录重叠子区间的个数&#xff0c;然后让整个数组的长度减去重叠的个数#…

基于springboot+vue+Mysql的滴答拍摄影项目

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Windows远程执行

Windows远程执行 前言 1、在办公环境中&#xff0c;利用系统本身的远程服务进行远程代码执行甚至内网穿透横向移动的安全事件是非常可怕的&#xff0c;因此系统本身的一些远程服务在没有必要的情况下建议关闭&#xff0c;防止意外发生&#xff1b; 2、作为安全人员&#xff0…