前言
现在,普遍的关系型数据库开发都离不开 mybatis 这个优秀的持久层框架。而在普遍的业务场景中,也时常会有短时间内高频次的增删操作。这样短时间内高频次的操作,通常有两种实现方案,第一种是比较常见的一种:在代码中编写循环,在持久层做单次的操作;另一种是通过 mybatis,直接在持久层批量操作数据。虽然mybatis 的批量也是在内存中操作的,但它从始至终只开了一个 sqlSession ,开销会比上一个方案小很多。
具体场景
比如现在有一个业务场景:
需要在 a,b,c 三个字段都相同的情况下,对比 d 字段,在一定条件下,取出一条记录(一整条)。
解决思路
- 首先,在不对表有任何更改的情况下,我试图用纯 sql 来解决问题。sql层面,在编写业务逻辑时,是无法规避 not in 或者 not exists 的,在数据量不大的情况下,这么写是没有问题。但当表格中的数据记录上万甚至是上十万后,这样的 sql 效率就会明显下降。
- 那么我们就采用第二个思路,对表格做出约束限制,通过 改表+sql 的形式,解决业务问题。
解决方案
- step1: 对表的三个字段做多字段组合唯一约束,告诉表格这三个字段只有组合起来才成立全表唯一。
ALTER TABLE table_a ADD UNIQUE(a,b,c)
-
step2: 建立批量查询语句,实现业务需求。
在开始第二步前,有两个知识点需要补充。
第一个知识点:mybatis 中的批量查询。 在 mybatis 中,批量 sql 拼接操作是通过 “< foreach >” 这个标签实现的。
简单的说三个参数:collection、item、separator。
collection值为要迭代循环的集合类型。
item:变量名,值为从迭代的对象中取出的每一个元素。
separator:拼在sql中的,每次循环得到元素的分隔符。第二个知识点:on duplicate key update 关键字。这个关键字代表的意思是,如果遇到唯一约束字段或者主键重复的话,执行 update 操作。values()框住的字段是代表从集合元素中取值,并 update 至对应字段。
具体代码:
<insert id="insertByBatchWithNotExist" parameterType="java.util.List">
insert into
table_a (a,b,c,d)
values
<foreach
collection="list" item="item" separator=",">
(
#{item.a},
#{item.b},
#{item.c},
#{item.d}
)
</foreach>
on duplicate key update
a = a + 1,
b = values(b),
c = values(c)
</insert>