原创

springboot+mytabtis_plus双数据源saveBtach/saveOrUpdate报错

作者:cndz 围观群众:755 更新于 标签:springboot双数据源mybaits_plusspringboot双数据源报错

问题

项目配置:springboot + mybatisPlus + 双数据源

1.最近给一个项目增加了某些功能,需要配置双数据源。结果发现在调用mybatis_plus的 saveBatch 或者 batchSave方法的时候报错,报错信息如下:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.TransactionManager' available: expected single matching bean but found 2: springTransactionManager,otherTransactionManager

分析

问题产生的原因呢,其实看下下面代码就知道了。

  public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {

      @Transactional(
            rollbackFor = {Exception.class}
        )
        public boolean saveBatch(Collection<T> entityList, int batchSize) {
            String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);
            return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {
                sqlSession.insert(sqlStatement, entity);
            });
        }


        @Transactional(
            rollbackFor = {Exception.class}
        )
        public boolean saveOrUpdate(T entity) {
            if (null == entity) {
                return false;
            } else {
                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]);
                Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty());
                return !StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal)) ? this.updateById(entity) : this.save(entity);
            }
        }
    }

原来mybatis_plus ServiceImplsaveBatchsaveOrUpdate 方法默认使用了。 @Transactional注解,在多数据源的情况下,使用 @Transactional需要指定 transactionManager。否则就会报开头的错误信息。

解决办法

其实解决办法很简单,在自己的service中重写自己用到的方法即可。

  public class DemoService extends ServiceImpl<DemoDao, Demo> implements DemoServiceImpl {
        @Override
      @Transactional(
              transactionManager = "springTransactionManager",
            rollbackFor = {Exception.class}
        )
        public boolean saveBatch(Collection<T> entityList, int batchSize) {
            String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);
            return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {
                sqlSession.insert(sqlStatement, entity);
            });
        }


        @Override
        @Transactional(
            transactionManager = "springTransactionManager",
            rollbackFor = {Exception.class}
        )
        public boolean saveOrUpdate(T entity) {
            if (null == entity) {
                return false;
            } else {
                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]);
                Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty());
                return !StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal)) ? this.updateById(entity) : this.save(entity);
            }
        }


        //其他业务逻辑。
    }

总结

其实需要注意的只有两点,配置双数据源使用 @Transcactional注解需要指定transactionManager。需要额外注意的是系统类似于MybatisPlus中的某些方法上的注解容易被忽略。解决办法呢就是重写需要用到的方法。当然,saveOrUpdate saveBatch方法只是举个例子。其他 @Transcactional在双数据源的使用场景下同样需要重写。