Mybatis对缓存提供支持,是默认开启一级缓存。
来一段代码,这边使用的是mybatis-plus框架,通过构建 QueryWrapper 查询类来实现的。
1 @Transactional 2 public ResData assginOrder1(List<SaleAssignData> assignlist) { 3 4 //此处省略很多代码 5 LocalDateTime now = LocalDateTime.now(); 6 assignlist.stream().forEach(data -> { 7 Integer projectId = data.getProjectId(); 8 Integer count = data.getCount(); 9 if(count != null && count >0){ 10 List<OrderDetailDO> list = orderDetailMapper.selectList(new QueryWrapper<OrderDetailDO>() 11 .eq("project_id", projectId).eq("agent_id", userId) 12 .eq("status",0).orderByAsc("id").last("limit" + count)); 13 14 Integer saleId = data.getUserId(); 15 SysUserDO saleman = sysUserMapper.selectById(saleId); 16 17 list.stream().forEach(orderDetailDO ->{ 18 //此处list处理 19 }); 20 orderDetailService.saveOrUpdateBatch(list); 21 } 22 }); 23 24 //此处其他表操作 25 26 return new ResData(); 27 }
如果传入的参数assignlist
[ { "projectId":1, "saleId":1, "count":1 }, { "projectId":1, "saleId":2, "count":1 } ]
在同一事务,两次查询条件,projectId和count值一样,原本认为第一次查询出的结果会被修改,可以顺利的修改成功。但事与愿违,两次查询得到的数据结果是一样,两次修改的是同一条数据,这就是因为mybatis一级缓存机制导致。
那么,怎么解决呢?以下提供两个方法
方法一:使用随机数方式,在sql处拼接一段随机数 【 .apply(num+"="+num) 】 ,让mybatis认为sql不一样
Random rn = new Random();
int num = rn.nextInt(100000);
List<OrderDetailDO> list = orderDetailMapper.selectList(new QueryWrapper<OrderDetailDO>().apply(num+"="+num) .eq("project_id", projectId).eq("agent_id", userId) .eq("status",0).orderByAsc("id").last("limit "+count));
方法二:springboot配置不使用一级缓存(默认是session级别),但是使用这种情况,一级缓存都不能使用,每次查询都要去数据库查询
mybatis.configuration.local-cache-scope=statement
这样就可以得到很好的解决。