项目有用到mybatis-plus还是挺香的,但是遇到一个坑
com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: can not find lambda cache for this property [dbName] of entity []
意思是实体类enetity及其字段没有缓存或者说指定字段没有缓存
这个需要具体问题具体分析,得先找到在哪缓存的?什么时候缓存的?
我这里的问题是因为继承太多
正常是一个mapper、一个serviceImpl继承官方提供的ServiceImpl
但是我这里在继承了ServiceImpl
之后又了两层继承
相当于这样
ReflectionKit.getSuperClassGenericType(getClass(), 1);
这里就解析不到实体类的具体类了,entityClass
变成了 Object
实体类缓存也就没有了
所以我重写了
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#currentModelClass
@Override
protected Class<T> currentModelClass() {
Type[] genericParamClassArray = ReflectUtil.getGenericParamClassArray(getClass());
if (genericParamClassArray == null || genericParamClassArray.length < 2) {
log.warn("Warn: {} not set the actual class on superclass generic parameter", getClass().getSimpleName());
return null;
}
return (Class<T>) genericParamClassArray[1];
}
-=============
ReflectUtil
/**
* 获取父类泛型 类型集合
* @param clazz
* @return
*/
public static Type[] getGenericParamClassArray(Class<?> clazz){
ParameterizedType genericSuperclass = getType(clazz);
if (genericSuperclass == null) {
throw new RuntimeException("Generic super class is null");
} else {
return genericSuperclass.getActualTypeArguments();
}
}
private static ParameterizedType getType(Class<?> clazz) {
for(int index = 0; index < 5; ++index) {
Type superType = clazz.getGenericSuperclass();
if (superType instanceof ParameterizedType) {
return (ParameterizedType)superType;
}
clazz = clazz.getSuperclass();
}
return null;
}
这样OK了
下面分析为啥
先看在哪缓存代码
com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper#getColumn
private String getColumn(SerializedLambda lambda, boolean onlyColumn) throws MybatisPlusException {
String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName());
Class<?> aClass = lambda.getInstantiatedType();
if (!initColumnMap) {
columnMap = LambdaUtils.getColumnMap(aClass);
initColumnMap = true;
}
Assert.notNull(columnMap, "can not find lambda cache for this entity [%s]", aClass.getName());
ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(fieldName));
Assert.notNull(columnCache, "can not find lambda cache for this property [%s] of entity [%s]",
fieldName, aClass.getName());
return onlyColumn ? columnCache.getColumn() : columnCache.getColumnSelect();
}
mybatis-plus 支持查询的时候用lambda 表达式来指定字段
baseMapper.selectOne(getLambdaQuery().eq(StationInfo::getAccount, account));
那么自动封装sql语句就需要解析到属性名从而获取到列名
报错信息也在这
如果当你debug到这里 columnMap
是空的,initColumnMap
又是true,那肯定是不对的
那么最开始initColumnMap
在哪赋值
com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper#initNeed
@Override
protected void initNeed() {
super.initNeed();
final Class<T> entityClass = getEntityClass();
if (entityClass != null) {
columnMap = LambdaUtils.getColumnMap(entityClass);
initColumnMap = true;
}
}
而上面的方法会在每次封装查询、修改AbstractLambdaWrapper
时调用
这里debug下什么都知道了,一般出问题是在
LambdaUtils.getColumnMap(entityClass)
我这里的问题是 entityClass
变成了Object
至于为啥这里是 Object
上面开始也说了
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
protected Class<?> entityClass = currentModelClass();
protected Class<T> currentModelClass() {
return (Class<T>) ReflectionKit.getSuperClassGenericType(getClass(), 1);
}
}