mybatis3.2.8踩坑记录之.size()

关于mybatis的xml标签使用问题和单元测试模拟高并发场景

标签使用问题

线上问题复现

Exception in thread "Thread-10" org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'null!=list and list.size()>0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [3] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class com.google.common.collect.Lists$TransformingRandomAccessList with modifiers "public"]
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:75)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:368)
    at com.sun.proxy.$Proxy26.selectList(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:198)

查询对应的xml

<select id="findUserProductDelaysByOrderNoAndProductId"
        resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from pe_user_product_delay where is_deleted = 0
        <if test="null!=list and list.size()>0">
            and status in
            <foreach collection="list" index="index" item="status" open="("
                separator="," close=")">
                #{status,jdbcType=INTEGER}
            </foreach>
        </if>
        <if test="productId != null and productId >= 0">
            and product_id =#{productId,jdbcType=INTEGER}
        </if>
        <if test="orderNo != null and orderNo !=''">
            and order_no =#{orderNo,jdbcType=VARCHAR}
        </if>
        and type in (1,2,3)
    </select>

问题就出现在list.size()这上面

目前的mybatis版本为3.2.8,框架对于传入的集合的调用size方法这部分并发控制的并不好,导致并发量稍微一高就会导致抛出异常,这里有一个关于这个问题的说明

https://zhuanlan.zhihu.com/p/30085658

此处建议:

不要在mybatis的xml中做一些调用集合函数方法等,所有的判断是否为空,判断集合大小这种操作都放到Java代码中执行,现有已存在的代码要尽快修改测试

单元测试模拟并发环境

public class UserProductDelayTest extends Junit4Base {
    @Autowired
    private IUserProductDelayService userProductDelayService;
    //模拟短时间内的并发请求量
    private static final int threadNum = 20;
    //倒计时器,用于模拟高并发
    private CountDownLatch cdl = new CountDownLatch(threadNum);

    @Test
    public void demo() {
        for (int i = 0; i < threadNum; i++) {
            new Thread(new UserRequest()).start();
            //倒计时计数一次
            cdl.countDown();
        }
        try {
            //阻塞主线程,等待所有的子线程执行完毕
            Thread.currentThread().join();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //
    private class UserRequest implements Runnable {

        @Override
        public void run() {
            try {
                cdl.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

          //此处进行写要并发测试的代码
            List<UserProductDelay> delayList =
                  userProductDelayService.findUserProductDelaysByOrderNoAndProductId("123123", 1, UserProductDelay.Status.AUDITEND);
            System.out.println(JSON.toJSONString(delayList));
        }
    }
}

利用CountDownLatch的特性实现模拟并发线程访问,建议所有的对外提供服务的service做单元测试的时候用这种方式自测一下

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,633评论 0 4
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,446评论 0 9
  • 我生性敏感,缺乏安全感和过分自卑。遇到点事常会设身处地的为他人着想,生怕自己言行举止惹得他人不愉快,然而最后才发现...
    维爱之都阅读 221评论 0 0
  • 前几日外出遇到一位小妹妹,她的言谈举止是那么大方,对自己自信满满,没有一点害羞或矜持的表现。 恰巧在转接车时我俩坐...
    暗香疏影手笔阅读 915评论 2 1
  • 1、各司其职的形状 在我的流程图中,适用于不同目的和功能的形状都有各自确定的规范。一共定义了以下一些形状: (1)...
    零一间阅读 1,187评论 0 2