一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
在实际业务中,我们经常会遇到一些批量插入数据的需求,比如导入一个excel文件,然后读取文件进行写数据,下面来介绍接种不同的批量插入方式。
一、Mybatis批量插入
1-1、通过for循环批量执行语句
1-1-1、EmpMapper.xml添加insert方法
如下图实现一个简单的插入操作
1-1-2、测试
首先先创建1000个Emp对象放入到List中,然后再通过for循环进行挨个插入,最终输出执行时间,如下:
1-2、通过设置batch执行器,for循环执行
Mybatis有三种执行器(默认:simple),分别为:
SIMPLE 就是普通的执行器;
REUSE 执行器会重用预处理语句(PreparedStatement);
BATCH 执行器不仅重用语句还会执行批量更新。
当前场景因为是批量执行,因此我们设置执行器为batch再次试一下
1-3、通过foreach拼接批量values执行语句。
批量执行语句如下,我们只需要通过foreach进行拼接插入的数据。
INSERT INTO emp (name,create_time)
VALUES
('张三丰的丰','2022-01-23 15:34:59'),
('李四','2022-02-23 15:34:59')
1-3-1、EmpMapper.xml添加xml
1-3-2、测试执行
如下:通过foreach执行,实际上对数据只进行了一次操作,这样执行时间久减少了很多,仅为264毫秒
1-4、通过foreach 设置批量insert
1-4-1、修改EmpMapper.xml
通过这种方式,最终就会将多个sql以“;”进行拼接。
1-4-2、设置数据库连接运行批量执行
数据库默认不允许进行批量执行多条语句,需要进行修改一下
allowMultiQueries=true
1-4-3、测试执行
1-3、使用foreach拼接sql
比如我们查询员工在研发部、销售部的人员,最原始的方式为dept_id in(1,2) 这样就可以实现了,1、2的传值方式只能为
select * from emp where dept_id in (${deptids})
这样操作会有一定风险,可能有sql注入的可能,因此我们可以使用foreach来进行处理
1-3-1、EmpMapper.xml配置
foreach标签中:
collection代表传入的集合/数组,
item代表每次迭代的值,
separator 代表每次迭代的值中间的分隔符。
上图中开头结尾写了(),这种情况在传入参数为空的情况下,会发生错误,如下图:
解决这种问题,我们也可以使用foreach的属性值去掉开头和结尾标签:
open:设置开头的值
close:设置结尾的值
这种情况如果传入的list为空也会发生异常,如下:
这种情况where无法进行判断处理了,因此需要给传入的值再进行判断
通过if对传入的集合再进行判断一次,这样就万无一失了。
1-4、使用set设置update语句
1-4-1、使用trim设置update语句
1-4-1-1、添加EmpMapper.xml 更新语句
如上,使用trim 设置了prefix 在开头添加 set,同时又设置了suffixOverrides作用是去掉最后一个, 这样在拼接sql的时候,就可以帮我们在开头加set 在结尾删除。
1-4-1-2、测试
1-4-2、使用set 设置update语句
1-4-2-1、添加empMapper.xml 更新语句
如上通过设置set,就不想trim那样繁琐,不用再设置开头和结尾了,set可以自动帮我们设置好。
1-4-2-2、测试
1-5、实现like语句查询
实现like语句查询语法为 like '%xx%',实现方式有:\
1-5-1、可以使用sql 语句的空格凭借如下:\
like '%' 'xx' '%'
1-5-2、使用concat 实现like 如下:
1-5-3、在业务层拼接好再传到xml中
如在业务处理逻辑中,可以直接拼接好语句如: %张% 然后传入xml中也可以实现like查询
1-5-4、使用bind实现like查询
使用bind标签,name属性为设置的变量值(可以随便),value为传入的值,并且可以使用OGNL表达式(OGNL表达式后面再介绍),这样value中的值最终变为 %张%,然后再吧name的值传入到sql中即可,如下:
1-6、sql代码片段的引入
我们在写sql的过程中,经常会写一些重复的sql语句,我们可以把这些重复的sql提取出来,然后再引入到各个sql中
1-6-1、创建代码片段,并通过引入
比如上面举例的示例中,select * from emp 多次出现,我们就可以把这段sql提取出来,然后再通过include引入的各个单独语句中。
1-6-2、sql片段和include的高级使用
有时候查询的字段可能有部分不一致,那么我们就可以设置部分字段来引入,include中有子节点,我们利用这个节点可以实现上述功能,property中有两个属性,分别为:
name:变量名(自定义的内容)
value:变量值(数据库字段,可以设置多个字段)
一般在sql片段中使用${}来引入property中的name属性值,如下:
如上面代码片段设置了 ${column}那么其他sql查询的地方在引入这个代码片段的时候就必须使用include的property设置name的值为cloumn。
1-7、Mybatis常用的ONGL表达式
e1 or e2
<if test="name=='张三' or name=='李四'">
e1 and e2
<if test="name=='张三' and name=='李四'">
e1 == e2,e1 eq e2
<if test="name=='张三' or name eq '李四'">
e1 != e2,e1 neq e2
<if test="name!='张三' or name neq '李四'">
e1 lt e2:小于
<if test="age lt 28">
e1 lte e2:小于等于,其他gt(大于),gte(大于等于)
<if test="age lte 28">
<if test="age gt 28">
<if test="age gte 28">
e1 in e2
<if test="name in('张三','李四')">
e1 not in e2
<if test="name not in('张三','李四')">
e1 + e2,e1 * e2,e1/e2,e1 ‐ e2,e1%e2
<if test="age +1 lt 26">
<if test="age*10 lt 26">
<if test="age/10 lt 26">
<if test="age-10 lt 26">
<if test="age%10 lt 26">
!e,not e:非,求反
<if test="! (name=='张三')">
<if test="not (name=='张三')">
e.method(args)调用对象方法
<if test="name.indexOf('张')>-1">
e1[ e2 ]按索引取值,List,数组和Map
<if test="list[0] eq '张三'">
@class@method(args)调用类的静态方法\
public static int getNum(){
return 10;
}
<if test="@com.jony.pojo.Emp@getNum() lt 10"
@class@field调用类的静态字段值
public static String Num=12;
<if test="@com.jony.pojo.Emp@Num gt 20">