【MyBatis系列7】原来SqlSession只是个甩手掌柜,真正干活的却是Executor等四大对象

我们在讲述MyBatis核心配置的文章中提到,配置文件中的setting标签内有一个属性defaultExecutorType,有三种执行类型:SIMPLEREUSEBATCH。如果不配置则默认就是SIMPLE。这三种类型就是对应了BaseExecutor的三个子类:

SimpleExecutorReuseExecutorBatchExecutor

SimpleExecutor

SimpleExecutor是最简单的一个执行器,没有任何特殊的,就是实现了BaseExecutor中的四个抽象方法。

我们来看其中一个doQuery()方法,可以看到没有任何特殊逻辑,就是很常规的流程操作:

在这里插入图片描述

其中初始化Statement对象我们为了对比,也进去看一下:

在这里插入图片描述

我们再来看一个doFlushStatements()方法

在这里插入图片描述

这里什么都没做,直接返回了一个空List

ReuseExecutor

ReuseExecutor相比较于SimpleExecutor做了一点优化,那就是将Statement对象进行了缓存处理,不会每次都创建Statement对象,这样做的话减少了SQL预编译和创建对象的开销。

ReuseExecutor中的查询和更新方法和SimpleExecutor完全一样,而其中的差别就在于创建Statement对象上,我们进去ReuseExecutor的prepareStatement方法:

在这里插入图片描述

我们可以看到区别就是多了一个从缓存中获取Statement对象的逻辑,用来达到复用Statement对象的目的。

其中getStatement是通过ReuseExecutor内的一个HashMap属性来获取Statement对象,其中key值就是我们执行的sql语句:

在这里插入图片描述

我们再来看看doFlushStatements方法,可以看到,这里面会遍历map将Statement关闭,并清空map,看到这里,大家应该就明白了为什么SimpleExecutor内这个方法直接返回的是空,因为SimpleExecutor方法没有Statement需要关闭。

在这里插入图片描述

PS:doFlushStatements方法在BaseExecutor中的commit(),rollback(),close()方法中会被调用(即:事务提交,事务回滚,事务关闭三个方法)。

BatchExecutor

BatchExecutor从名字上也可以看出来,这是一个支持批量操作的执行器。

如果说大家都用过jdbc就知道,jdbc是支持批量操作的,有一个executeBatch()方法用来执行批量操作,但是有一个前提就是执行批量操作的sql除了参数不同,其他都应该是相同的(关于这一点,下面我们会举例来说明)。

需要注意的是,批量操作只支持insert,update,delete语句,select语句是不支持的,所以BatchExecutor内的doQuery方法和其他执行器并没有很大不同,区别就是在查询之前会先调用flushStatements(),我们不做过多讨论,主要看一下doUpdate方法:

在这里插入图片描述

下面是一些成员属性:

在这里插入图片描述

这个方法的逻辑就是判断相同模式的sql会共用同一个Statement对象,然后缓存到list内,需要注意的是它只会和前一个进行比对,也就是说假如你有相同模式的2条sql,但是你中间先执行了一条其他sql,那么就会产生3个Statement对象,从而无法共用了。

PS:上面的doUpdate中返回了一个数:BATCH_UPDATE_RETURN_VALUE,这个数其实没有什么特别含义,只需要返回一个没有意义的负数就可以,表示代码不知道执行成功多少条。比如说直接返回-1,或者干脆直接返回Integer.MIN_VALUE都是没有问题的,全凭个人喜好了。

接下来我们再看看doFlushStatements()方法:

在这里插入图片描述

这个方法就是去遍历上面存储好的Statement,依次调用Statement中的executeBatch方法。

三种常用批量插入方式

讲到这里,我们就干脆扯开一点,聊一聊MyBatis编程中常用的三种批量操作方式。

直接代码循环

这是最简单的一种,但也是效率最低的一种,如下简单示例:

UserAddressMapper userAddressMapper = session.getMapper(UserAddressMapper.class);

for (UserAddress userAddress : userAddressList){

userAddressMapper.insert(userAddress);

}

这种方式会把大部分时间消耗在网络连接通信上,一般不建议使用。

利用MyBatis中批量标签foreach处理

新建测试类:

package com.lonelyWolf.mybatis.batch;

import com.lonelyWolf.mybatis.mapper.UserAddressMapper;

import com.lonelyWolf.mybatis.model.UserAddress;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.List;

public class TestBatchInsert {

public static void main(String[] args) throws IOException {

String resource = “mybatis-config.xml”;

//读取mybatis-config配置文件

InputStream inputStream = Resources.getResourceAsStream(resource);

//创建SqlSessionFactory对象

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//创建SqlSession对象

SqlSession session = sqlSessionFactory.openSession();

try {

List userAddressList = new ArrayList<>();

UserAddress userAddr = new UserAddress();

userAddr.setAddress(“广东深圳”);

userAddressList.add(userAddr);

UserAddress userAddr2 = new UserAddress();

userAddr2.setAddress(“广东广州”);

userAddressList.add(userAddr2);

UserAddressMapper userAddressMapper = session.getMapper(UserAddressMapper.class);

userAddressMapper.batchInsert(userAddressList);

session.commit();

}finally {

session.close();

}

}

}

Mapper接口新增如下方法:

int batchInsert(List userAddresses);

XML文件如下:

insert into lw_user_address (address) values

(#{item.address})

执行之后输出如下语句:

在这里插入图片描述

顺便我们介绍一下foreach标签的用法:

  • collection

表示待循环的对象。当参数为List时,默认"list",参数为数组时,默认"array"。但是当我们在Mapper接口中使用@Param(“xxx”)时,默认的list,array将会失效,必须使用我们自己设置的参数名。 还有一种特殊情况就是假如集合里面有集合或者对象里面有集合,那么可以使用collection=“xxx.属性名”。

  • item

表示当前循环中的元素。

  • open/close,表示循环体开始和结束位置插入的符号,一般成对出现,in语句使用较多,如:

select * from xxx where id in

#{item.xxx}

  • separator:表示每个循环之后的分割符号,可参考上面的例子

  • index:当前元素在集合的下标,如果是map则是map的key值,这个参数一般用的相对较少。

BatchExecutor插入

我们把上面的普通例子中获取Session的例子改写一下:

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);

如果想详细了解openSession方法参数的,可以点击这里。然后执行之后输出sql如下:

在这里插入图片描述

可以看到,这两条语句就是相同模式的sql,只是参数不同,所以直接执行一次。

我们把上面的例子改写一下:

UserAddress userAddr = new UserAddress();

userAddr.setAddress(“广东深圳”);

userAddr.setId(1);

userAddressList.add(userAddr);

UserAddress userAddr2 = new UserAddress();

userAddr2.setAddress(“广东广州”);

userAddr2.setId(2);

userAddressList.add(userAddr2);

UserAddressMapper userAddressMapper = session.getMapper(UserAddressMapper.class);

userAddressMapper.insert(userAddr);//sql-1

userAddressMapper.insert10(userAddr2);//sql-10

userAddressMapper.insert(userAddr);//sql-1

insert和insert10分别对应如下语句(一条是1个参数,一条是2个参数):

insert into lw_user_address (address) values (#{address})

insert into lw_user_address (id,address) values (#{id},#{address})

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?

掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
csdnimg.cn/images/e5c14a7895254671a72faed303032d36.jpg" alt=“img” style=“zoom: 33%;” />

最后

面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?

掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。

[外链图片转存中…(img-kQBhfX70-1712706016845)]

[外链图片转存中…(img-50DvmSqF-1712706016845)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值