mybaits缓存造成的数据错误

/ 后端 / 没有评论 / 228浏览

1.问题复现

(1) 原有一处老的查询业务,循环列表然后依次查询数据库内容,插入到列表对象中展示,先不说遗留代码的查询性能问题;出现了展示的列表中对象数据重复问题; (2) 伪代码:

for(EntityList entity: entitys){
  //数据库中查询商品信息
  Integer goodsId = entity.getGoodsId();
  GoodsInfo goodsInfo = goodsMapper.queryById(goodsId);
  //列表对象中保存有不同的描述信息,并赋值到商品信息对象
  String desc = entity.getDesc();
  goodsInfo.setDesc(desc);
   
  //将商品信息对象赋值到列表对象
  entity.setGoodsInfo(goodsInfo);
}

(3)出现数据重复错误原因:   由于该方法开启了事务@Transactional.导致mybatis默认开启了一级session级别缓存LocalCache,所以在同一session中,查询相同的sql返回的是缓存的同一个对象;   所以,当 goodsMapper.queryById(goodsId)查询的goodsId相同时,除了第一次,后面都是执行的查询缓存,所以返回的 GoodsInfo goodsInfo 是同一个,导致了后面赋值不同desc会被最后一个所覆盖,列表不同对象entity.setGoodsInfo(goodsInfo)也即是同一个GoodsInfo对象;

2.解决问题

(1)改进业务代码,避免出现类似的循环查询相同sql导致缓存的问题; (2)设置一级缓存,statement级别的缓存每一次查询后清除; session级别缓存在同一个SqlSession的insert、update、delete操作之前清除

 @Bean
    public SqlSessionFactoryBean wfSqlSessionFactoryBeanPro(@Qualifier("dataSource") DataSource datasource) {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setTypeAliasesPackage("com.wfcm.entity");
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(NoLoggingImpl.class);// 不输出日志()
        //   configuration.setLogImpl(WfStdOutImpl.class);//标准输出日志
        configuration.setMapUnderscoreToCamelCase(true);// 开启驼峰命名
        configuration.setCallSettersOnNulls(true);// 开启在属性为null也调用setter方法
        configuration.setDefaultStatementTimeout(180);//默认超时
        configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
        bean.setConfiguration(configuration);
        return bean;
    }