当前使用版本(必填,否则不予处理)

3.4.3版本,没有问题

该问题是如何引起的?(确定最新版也有问题再提!!!)

更新版本到3.4.3.2及以上

仅仅升级了版本出现了问题,确认是mybatis-plus内部代码问题

重现步骤(如果有就写完整)

mybatis-plus-boot-starter 从3.4.3升级到3.4.3.2版本或以上版本

我的代码:

  1. 调用代码

downloadService.saveOrUpdateBatch(updateItemList, Item.class, Item::getExamId, Item::getItemCode);

updateItemList --数据列表(Item)

  1. downloadService的实现

`

@Transactional(rollbackFor = Exception.class) public boolean saveOrUpdateBatch(Collection<? extends BaseEntity> entityList,Class entityClass,SFunction...columns) { return saveOrUpdateBatch(entityList, ServiceImpl.DEFAULT_BATCH_SIZE,entityClass,columns); }

@Transactional(rollbackFor = Exception.class)
public <T> boolean saveOrUpdateBatch(Collection<? extends BaseEntity<T>> entityList, int batchSize, Class<T> entityClass, SFunction<T,?>...columns) {
    TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
    Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!");
    String keyProperty = tableInfo.getKeyProperty();
    Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!");
    return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
        Object idVal = ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty());
        boolean insert = true;
        if (columns != null && columns.length > 0 && StringUtils.checkValNull(idVal)) {
            T t = selectOne(tableInfo,sqlSession,(T)entity,columns);--------------------报错方法
            if (t != null) {
                idVal = ReflectionKit.getFieldValue(entity, keyProperty);
                insert = false;
            }
        }
        if (insert) {
            //不添加已删删除数据
            if (entity.getIsDelete() == null || entity.getIsDelete() == GeneralEnums.DeleteEnums.NO.getKey()) {
                entity.setUpdateInfo(entity.getUpdateUser(), true);
                sqlSession.insert(tableInfo.getSqlStatement(SqlMethod.INSERT_ONE.getMethod()), entity);
            } else {
                entity.setId(null);
            }
        } else {
            entity.setUpdateInfo(entity.getUpdateUser(),false);
            MapperMethod.ParamMap<Object> param = new MapperMethod.ParamMap<>();
            UpdateWrapper updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq(tableInfo.getKeyColumn(),idVal);
            //更新删除标识,防止唯一约束冲突
            if (entity.getIsDelete() != null && entity.getIsDelete() != GeneralEnums.DeleteEnums.NO.getKey()){
                updateWrapper.set("is_delete",IdWorker.getId());
            }
            param.put(Constants.ENTITY, entity);
            param.put(Constants.WRAPPER,updateWrapper);
            sqlSession.update(tableInfo.getSqlStatement(SqlMethod.UPDATE.getMethod()), param);
        }
    },entityClass);
}
protected <E> boolean executeBatch(Collection<? extends BaseEntity<E>> list, int batchSize, BiConsumer<SqlSession, BaseEntity<E>> consumer, Class<E> entityClass) {
    Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
    return !CollectionUtils.isEmpty(list) && executeBatch(sqlSession -> {
        int size = list.size();
        int i = 1;
        for (BaseEntity<E> element : list) {
            consumer.accept(sqlSession, element);
            if ((i % batchSize == 0) || i == size) {
                sqlSession.flushStatements();
            }
            i++;
        }
    },entityClass);
}
protected boolean executeBatch(Consumer<SqlSession> consumer, Class entityClass) {
    SqlSessionFactory sqlSessionFactory = SqlHelper.sqlSessionFactory(entityClass);
    SqlSessionHolder sqlSessionHolder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sqlSessionFactory);
    boolean transaction = TransactionSynchronizationManager.isSynchronizationActive();
    if (sqlSessionHolder != null) {
        SqlSession sqlSession = sqlSessionHolder.getSqlSession();
        //原生无法支持执行器切换,当存在批量操作时,会嵌套两个session的,优先commit上一个session
        //按道理来说,这里的值应该一直为false。
        sqlSession.commit(!transaction);
    }
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    if (!transaction) {
        log.warn("SqlSession [" + sqlSession + "] was not registered for synchronization because DataSource is not transactional");
    }
    try {
        consumer.accept(sqlSession);
        //非事物情况下,强制commit。
        sqlSession.commit(!transaction);
        return true;
    } catch (Throwable t) {
        sqlSession.rollback();
        Throwable unwrapped = ExceptionUtil.unwrapThrowable(t);
        if (unwrapped instanceof RuntimeException) {
            MyBatisExceptionTranslator myBatisExceptionTranslator
                    = new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true);
            throw Objects.requireNonNull(myBatisExceptionTranslator.translateExceptionIfPossible((RuntimeException) unwrapped));
        }
        throw ExceptionUtils.mpe(unwrapped);
    } finally {
        sqlSession.close();
    }
}

/**
 * 根据id查询
 * @param tableInfo
 * @param sqlSession
 * @param <T>
 * @return
 */
public <T>T selectById(TableInfo tableInfo,SqlSession sqlSession){
    return sqlSession.selectOne(tableInfo.getSqlStatement(SqlMethod.SELECT_BY_ID.getMethod()));
}

---保错方法 public T selectOne(TableInfo tableInfo, SqlSession sqlSession,T entity, SFunction...columns){ Map parame = new HashMap<>(); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.select(tableInfo.getKeyColumn()); if (columns != null && columns.length > 0){ for (SFunction function : columns){ Object val = function.apply(entity); //不为空 if(Objects.isNull(val)){ queryWrapper.lambda().isNull(function); }else{ queryWrapper.lambda().eq(function,val); } } }else{ return null; } parame.put(Constants.WRAPPER,queryWrapper);

   **实际报错代码**
    return sqlSession.selectOne(tableInfo.getSqlStatement(SqlMethod.SELECT_ONE.getMethod()),parame);
}

`

  1. 说明

实际报错方法 sqlSession.selectOne(tableInfo.getSqlStatement(SqlMethod.SELECT_ONE.getMethod()),parame);

仅仅升级了版本出现了问题,确认是mybatis-plus内部代码问题

报错信息

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:

Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.fplcloud.exam.modules.system.mapper.ItemMapper.selectOne

Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.fplcloud.exam.modules.system.mapper.ItemMapper.selectOne

at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96)
at com.fplcloud.exam.modules.examsystem.service.DownloadService.executeBatch(DownloadService.java:998)
at com.fplcloud.exam.modules.examsystem.service.DownloadService.executeBatch(DownloadService.java:961)
at com.fplcloud.exam.modules.examsystem.service.DownloadService.saveOrUpdateBatch(DownloadService.java:926)
at com.fplcloud.exam.modules.examsystem.service.DownloadService.saveOrUpdateBatch(DownloadService.java:918)
at com.fplcloud.exam.modules.examsystem.service.DownloadService$$FastClassBySpringCGLIB$$1cff083c.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
at com.fplcloud.exam.modules.examsystem.service.DownloadService$$EnhancerBySpringCGLIB$$10b7ab14.saveOrUpdateBatch(<generated>)
at com.fplcloud.exam.modules.examsystem.service.Impl.ExamSystemItemServiceImpl.saveExamItem(ExamSystemItemServiceImpl.java:167)
at com.fplcloud.exam.modules.examsystem.service.Impl.ExamSystemItemServiceImpl$$FastClassBySpringCGLIB$$39e8cad7.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
at com.fplcloud.exam.modules.examsystem.service.Impl.ExamSystemItemServiceImpl$$EnhancerBySpringCGLIB$$79862c1e.saveExamItem(<generated>)
at com.fplcloud.exam.modules.system.service.impl.AsyncServiceImpl.downloadServerData(AsyncServiceImpl.java:126)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)

Comment From: nieqiurong

3.4.3.2已经删除了selectOne方法的注入了,你可以将方法注入一下.

Comment From: przygrubyu5

好的,我已经添加了

`public class DownSqlInjector extends DefaultSqlInjector { @Override public List getMethodList(Class<?> mapperClass, TableInfo tableInfo) { List methodList = super.getMethodList(mapperClass, tableInfo); methodList.add(new SelectOne()); return methodList; }

}`

Comment From: nieqiurong

好的,我已经添加了

`public class DownSqlInjector extends DefaultSqlInjector { @OverRide public List getMethodList(Class<?> mapperClass, TableInfo tableInfo) { List methodList = super.getMethodList(mapperClass, tableInfo); methodList.add(new SelectOne()); return methodList; }

}`

也能自己改动一下调用selectList把,那样和后面的也匹配点.