mybatis-plus使用上需要注意的问题
1.问题产生
之前,开发项目使用的是tk-mapper,当使用批量操作时,通常使用insertList就可以了。但是,最近的项目使用的是mybaits-plus,在使用批量操作saveBatch的使用,却遇到了一个问题,这个一开始让我以为我的数据出现了重复,但是仔细看,不是数据出现了重复,而是因为有一个字段相同,报唯一索引字段重复插入 Duplicate entry。
下面是我插入数据的sql和相对应的数据信息:

但是插入却报了错:

第一个感觉很诧异,批量插入操作,为啥还报了唯一索引异常了呢。
2.查看mybatis-plus封装代码
可以看到其批量操作的本质是一个for循环操作,注意参数里面出现了ignore:
/**
* 批量插入
* @param entityList ignore
* @param batchSize ignore
* @return ignore
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
int size = entityList.size();
executeBatch(sqlSession -> {
int i = 1;
//遍历需要插入的数据列表,也即将数据想打包,然后执行批量操作
for (T entity : entityList) {
sqlSession.insert(sqlStatement, entity);
if ((i % batchSize == 0) || i == size) {
sqlSession.flushStatements();
return true;
同时还可以看到其插入操作底层却是更新操作。
@Override
public int insert(String statement, Object parameter) {
return update(statement, parameter);
可以看到mybatis的执行器执行的是更新方法:
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
而当插入数据完成后,刷新语句,然后执行批量操作
/**
* 执行批量操作
* @param fun fun
* @since 3.3.0
protected void executeBatch(Consumer<SqlSession> fun) {
Class<T> tClass = currentModelClass();
SqlHelper.clearCache(tClass);
SqlSessionFactory sqlSessionFactory = SqlHelper.sqlSessionFactory(tClass);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
fun.accept(sqlSession);
sqlSession.commit();
} 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();