MybatisPlusExcepection: can not find lambda cache for this property [XX] for entity [xxx]

项目有用到mybatis-plus还是挺香的,但是遇到一个坑
com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: can not find lambda cache for this property [dbName] of entity []
意思是实体类enetity及其字段没有缓存或者说指定字段没有缓存

这个需要具体问题具体分析,得先找到在哪缓存的?什么时候缓存的?

问题和解决方案

我这里的问题是因为继承太多
正常是一个mapper、一个serviceImpl继承官方提供的ServiceImpl
但是我这里在继承了ServiceImpl之后又了两层继承
相当于这样
MybatisPlusExcepection: can not find lambda cache for this property [XX] for entity [xxx]_第1张图片

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时调用
MybatisPlusExcepection: can not find lambda cache for this property [XX] for entity [xxx]_第2张图片
这里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);
    }
}

你可能感兴趣的:(mybatis-plus,mybatis)