• 分析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挂掉)

  • 相关阅读:
    小白详细解析C#反射特性实例
    几种快速排序算法实现
    Redis中算法之——Raft算法
    redis中算法之——MurmurHash2算法
    关于typedef的用法
    gdb调试工具常用命令
    gcc 常用命令
    Linux 远程登录ssh服务器
    Linux 构建ftp服务器
    知乎话题结构以及相关内容抓取二(Redis存储)
  • 原文地址:https://www.cnblogs.com/aspirant/p/16712068.html
Copyright © 2020-2023  润新知