前段时间开发过程中碰到了因为mybatis一级缓存导致对象被重复添加到list的问题,在此记录一下
参考博客:https://www.cnblogs.com/happyflyingpig/p/7739749.html
https://blog.csdn.net/j7636579/article/details/73647885
项目场景:
因为mybatis一级缓存导致对象被重复添加到list
问题描述:
对象A--约束条件,
对象B--需要查询出的对象
Date date = new Date();
List<A> as = new ArrayList<A>();
A a = new A();
a.setDate(date);
a.setProductId(1);
....
A a1 = new A();
a1.setDate(date);
a1.setProductId(1);
....
as.add(a);//a和a1的属性一致
as.add(a1);
List<B> result = new ArrayList<B>();
int i = 0;
for(A a : as) {
//对象A的属性查询B的约束条件,呈现的sql select * from B where date< a.date and productId = a.productId;
B date= Bservice.selectB(a);//由于两次查询条件一致,若开启一级缓存,会导致第二次查询返回的是第一次的结果集,对象引用也和第一次一致
//第一次返回 B ={id=1,name=2,...,count=1}
date.setCount(i++);//对查出的对象属性赋值
result .add(date);
}
//result 输出后 [{id=1,name=2,...,count=2},{id=1,name=2,...,count=2}]
Class A{
Date date;
int productId;
.....
}
Class B{
int id;
String name;
Date date;
int productId;
int count;
.....
}
原因分析:
开启一级缓存后,查询条件不变,sqlSession 不变,查询返回的结果集也不变,导致了两次查出的对象是同一个
解决方案:
关闭一级缓存,自己尝试了不少方法包括在mapper文件中配置 flushCache="true" useCache="false" ,springboot配置关闭一级缓存---都无效
还有就是调用SqlSession.clearCache(),这种自己没有尝试过
直接在整合mybatis的代码中设置LocalCacheScope属性
@Component
@Configuration
public class MmsMybatisConfig {
//注入WmfDataSourceConfig中配置的ComboPooledDataSource是c2p0的实现标准
@Autowired
private DataSource dataSource;
private static Logger logger = LoggerFactory.getLogger (MmsMybatisConfig.class);
@Bean(name = "sqlSessionFactory.cms")
public SqlSessionFactoryBean sqlSessionFactoryBeanGwcmp() {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean ();
bean.setDataSource (dataSource);
/**
* 关闭一级缓存
*/
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
bean.setConfiguration(configuration);
/**
* <array>
* </array>
*/
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver ();
String[] path = new String[] {"classpath*:mapper/*.xml","classpath*:com/aspire/boc/settle/*dao/*mapper/*.xml"};
List<Resource> arrayList = new ArrayList<> ();
try {
for (String s : path ) {
List<Resource> asList = Arrays.asList (resolver.getResources (s));
arrayList.addAll (asList);
}
}
catch (IOException e ) {
throw new RuntimeException (e);
}
bean.setMapperLocations (arrayList.toArray (new Resource[arrayList.size ()]));
try {
logger.info ("bean creat success Mapper [{}]",arrayList.size ());
return bean;
}
catch (Exception e ) {
logger.info ("bean creat error!");
e.printStackTrace ();
throw new RuntimeException (e);
}
}
}