分析mybatis的#{}、${}(#绑定变量超过一定值导致Oracle挂掉)

我后来改成了1万条,数据库相对小点 压力不大,也不会出现重启的问题;

 

最近跟数据库干上了
先说下问题起源,算奖确认订单,需要批量update订单,查了相关资料,是mybatis一次性绑定变量超过65535(这个数值并不准,因为后来绑定变量超过一万一又导致Oracle挂掉一次),引发了Oracle的一个bug,导致数据库宕机

mybatis 引入参数#和$区别
1.#是绑定变量的形式,底层会用#{}会被替换为?号,有参数映射,会在DefaultParameterHandler中进行设置占位符的操作;当使用$的时候,{value}是直接被替换为了对应的值,没有参数映射,不会进行设置占位符的操作

2.$不安全,可以被sql注入(使用时注意),#相对安全

测试
用批 量 更 新 没 有 绑 定 变 量 的 问 题 , 但 是 这 种 写 法 由 于 是 直 接 替 换 参 数 , 有 安 全 风 险 , 需 要 注 意 的 是 ; 批量更新没有绑定变量的问题,但是这种写法由于是直接替换参数,有安全风险,需要注意的是;批量更新没有绑定变量的问题,但是这种写法由于是直接替换参数,有安全风险,需要注意的是;{}这种取值方式,字符串类型需要加单引号

<update id="updateTable">
<foreach collection="params" item="item" index="index" open="begin" close=" ; end ;" separator=";">
update table
<set>
win_detail=${item.winDetail},
declaration=${item.declaration},
currency_Id=${item.currencyId},
activity_Type=${item.activityType}
</set>
where id=${item.id}
</foreach>
</update>
1
2
3
4
5
6
7
8
9
10
11
12
而用#这种写法,是绑定变量的,批量更新,一次性更新绑定变量超过一定数值就会有问题(可以批次更新数量少一些,如果数据量庞大,可以用多线程去跑),Oracle数据库即使打了补丁不会导致直接宕机,也会直接抛错执行不成功,这种用法一定要注意批次更新绑定变量数量,切记,切记!!!

<update id="updateTable">
<foreach collection="params" item="item" index="index" open="begin" close=" ; end ;" separator=";">
update table
<set>
win_detail=#{item.winDetail},
declaration=#{item.declaration},
currency_Id=#{item.currencyId},
activity_Type=#{item.activityType}
</set>
where id=#{item.id}
</foreach>
</update>
1
2
3
4
5
6
7
8
9
10
11
12
用上面这种方式,单线程跑15000条以上数据,数据库必挂,换一下思路,分批处理,一次处理500条,用多线程去跑,没问题

@Test
public void testBatch(){
List<ParamTest> testList = new ArrayList<ParamTest>();
List<AwardLotteryVO> ltList = awardMapper.getLtList();

for(AwardLotteryVO vo : ltList){
ParamTest t = new ParamTest();
t.setActivityType("1");
t.setCurrencyId(-1L);
t.setDeclaration("我必中");
t.setWinDetail("ok");
t.setBetId(vo.getBetId());
testList.add(t);
System.out.println(vo.getBetId());
}
Long start = System.currentTimeMillis();
//切割list,一次处理500条数据
List<List<ParamTest>> splitList = AwardUtils.splitList(testList, 500);
for(int i = 0; i < splitList.size(); i ++){
List<ParamTest> list = splitList.get(i);
System.out.println("执行第 " + i + " 次");
ThreadPool.putThread(new AwardConfirmTest(awardMapper, list));
}
System.out.println("----------end-----------------" + (System.currentTimeMillis() - start));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
以后工作或学习中,在使用相关工具、相关框架时还是需要弄清楚工具或者框架的工作原理,不断学习,才能游刃有余,临危不乱~

问题解决多亏了这两篇博客,Oracle实例重启事故分析 & 关于Mybatis的$和#,你真的知道他们的细节吗?
链接如下:
https://www.jianshu.com/p/f70d8bbee075
https://www.jianshu.com/p/d0fc693fc888
————————————————
参考:分析mybatis的#{}、${}(#绑定变量超过一定值导致Oracle挂掉)

posted @ 2022-09-20 18:21  aspirant  阅读(439)  评论(0编辑  收藏  举报