问题场景
自己搭建了一套SpringBoot项目,在后期的开发中,欲将mybatis平滑升级为mybatis-plus升,基本升级完毕,在调用IService的saveOrUpdateBatch进行批量新增记录或者更新记录的时候遇到了问题"error: can not execute. because can not find cache of TableInfo for entity!",进行代码追踪如下:
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
String keyProperty = tableInfo.getKeyProperty();
Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> {
Object idVal = ReflectionKit.getFieldValue(entity, keyProperty);
return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(this.getSqlStatement(SqlMethod.SELECT_BY_ID), entity));
}, (sqlSession, entity) -> {
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap();
param.put("et", entity);
sqlSession.update(this.getSqlStatement(SqlMethod.UPDATE_BY_ID), param);
});
}
进入方法获取TableInfo对象:
TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
我们会看到如下代码:
public static TableInfo getTableInfo(Class<?> clazz) {
if (clazz != null && !ReflectionKit.isPrimitiveOrWrapper(clazz) && clazz != String.class && !clazz.isInterface()) {
Class<?> targetClass = ClassUtils.getUserClass(clazz);
TableInfo tableInfo = (TableInfo)TABLE_INFO_CACHE.get(targetClass);
if (null != tableInfo) {
return tableInfo;
} else {
for(Class<?> currentClass = clazz; null == tableInfo && Object.class != currentClass; tableInfo = (TableInfo)TABLE_INFO_CACHE.get(ClassUtils.getUserClass(currentClass))) {
currentClass = currentClass.getSuperclass();
}
if (tableInfo != null) {
TABLE_INFO_CACHE.put(targetClass, tableInfo);
}
return tableInfo;
}
} else {
return null;
}
}
问题代码行:
TableInfo tableInfo = (TableInfo)TABLE_INFO_CACHE.get(targetClass);
现在我的mybatis升级为mybatis-plus的操作以及相关解决方案分享如下:
依赖包替换
将pom文件中原来mybatis依赖替换为baomidou的mybatis-plus依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
这里有一个小坑,就是mybatis-puls的版本问题,如果小伙伴们不注意,运气不好,会遇到版本不匹配问题,我是完美的跳坑了。我是有一个相迫症是一切从新a,就想用最新的,最后还是败给了版本。
mybatisPlusConfig配置文件修改
依赖包替换并更新依赖后,就该修改配置文件了,将MyBatisConfig配置文件中的@Bean注释掉,当然,这里却决于你,你也可以直接在在原来的配置上做修改,我新建一个新的类MyBatisPlusConfig,所以呢将原来的@Bean注解注释掉让其配置不生效就好了。
MyBatisPlusConfig中的配置文件:
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
String configLocation = env.getProperty("mybatis-plus.configLocation");
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
VFS.addImplClass(SpringBootVFS.class);
final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
return sessionFactory.getObject();
}
将SpringBootVFS,MybatisSqlSessionFactoryBean群不替换为baomidou包想的相应文件。yml的配置文件做相应的修改即可。
报错原因
万恶之源在这里,MyBatis-Plus应该使用MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean。MybatisPlusAutoConfiguration的源码中,如果已经有配置SqlSessionFactory。MyBatis-Plus将不会自动帮我们注入SqlSessionFactory,而使用我们自己定义的SqlSessionFactory。而我当时是没有替换掉mybatis的SqlSessionFactoryBean,在MyBatisPlusConfig里还是用的
import org.mybatis.spring.SqlSessionFactoryBean;
所以,mybatis-plus中TableInfoHelper的TABLE_INFO_CACHE根据字节码对象获取不到对应的TableInfo对象。
解决方案就相应的接知道了撒:
直接替换掉SqlSessionFactoryBean,换位MybatisSqlSessionFactoryBean就可以了。
补充
在入坑之后呢,我查阅相关资料,发现其他大佬也有遇到相关问题,但是原因和解决方案都是不一样的,这里附上链接,可参考:
https://blog.csdn.net/weixin_43401380/article/details/108863687