【MyBatis-Plus】之批量插入

一、应用情景介绍


在实际的项目开发过程中,常常遇到批量保存数据的场景,当数据量比较少,比如只有几条数据的情况下,我们可以使用 for 循环来 insert 数据,但如果数据量比较多的情况下就不行,特别是并发的情况下,因为这样会增加数据库的负担。

我们通过查看 mybatis-plus 源码发现,mybatis-plusIService API 接口提供了批量插入的接口:

public interface IService<T> {
    ......
    /**
     * 插入(批量)
     *
     * @param entityList 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean saveBatch(Collection<T> entityList) {
        return saveBatch(entityList, DEFAULT_BATCH_SIZE);
    }
    ......

查看该批量插入的实现方法源码:

public boolean saveBatch(Collection<T> entityList, int batchSize) {
    String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
    try (SqlSession batchSqlSession = sqlSessionBatch()) {
        int i = 0;
        // 在for循环中循环调用insert
        for (T anEntityList : entityList) {
            batchSqlSession.insert(sqlStatement, anEntityList);
            if (i >= 1 && i % batchSize == 0) {
                batchSqlSession.flushStatements();
            }
            i++;
        }
        batchSqlSession.flushStatements();
    }
    return true;
}

从源码可以看到,所谓的批量插入就是一个 for 循环插入,很明显,这不是我们想要结果。而当我们继续阅读 mybatis-plus 的源码可以发现,在 com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn 包中已经为我们实现了真正意义上的批量插入方法,这里就不贴实现的源码了,有兴趣的可以去看看。

因此,我们需要做的就是生效该批量了插入方法,从而可以让我们通过 Mapper 来调用它。


二、实现批量插入


1、引入依赖


<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.4.0version>
dependency>


<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-extensionartifactId>
    <version>3.4.0version>
dependency>

2、编写自定义SQL注入类

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;

import java.util.List;

/**
 * @Description: 支持自定义SQL注入方法
 * @author 王廷云
 * @date 2021/9/8 16:58
 */
public class CustomSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        // 获取父类SQL注入方法列表
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        // 将批量插入方法添加进去
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }

}

在这里,我们先获取默认的 SQL 注入方法列表,然后再讲批量插入方法添加进去。默认的方法列表有哪些呢,下面是我通过断点调试的截图:
【MyBatis-Plus】之批量插入_第1张图片
可以看到,默认就是我们常用的 InsertDeleteUpdateSelectOne 等方法。

3、将该类注入到 Bean 中

@Configuration
public class MybatisPlusConfig {

    @Bean
    public CustomSqlInjector customSqlInjector() {
        return new CustomSqlInjector();
    }

}

4、将批量插入方法扩展进 BaseMapper 中

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.Collection;

/**
 * 自定义Mapper,添加批量插入接口
 */
public interface CustomMapper<T> extends BaseMapper<T> {

    /**
     * 批量插入
     * @param entityList 实体列表
     * @return 影响行数
     */
    Integer insertBatchSomeColumn(Collection<T> entityList);

}

注意: 不要忘记在启动类 Application 中添加 @MapperScan(basePackages = "xxx.xxx") 使该 Mapper 被扫描到。

5、测试验证

1)在数据库中创建用户表

CREATE TABLE `user`(
	`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '主键',
	`name` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '姓名',
	`age` INT(4) NOT NULL DEFAULT 0 COMMENT '年龄',
	PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

2)编写实体类

@Data
@Accessors(chain = true)
@TableName("user")
public class User {

    @TableId(type = IdType.AUTO)
    private Integer id;

    @TableField(value = "name")
    private String name;

    @TableField(value = "age")
    private Integer age;

}

3)编写 Mapper 接口

public interface UserMapper extends CustomMapper<User> {
}

4)编写 DAO 层

@Repository
public class UserDao {

    @Autowired
    private UserMapper userMapper;

    public void insertBatch(List<User> userList) {
        userMapper.insertBatchSomeColumn(userList);
    }

}

5)编写 Service 层

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    /**
     * 批量插入用户
     */
    public void insertUserBatch() {
        List<User> list = new ArrayList<>();
        list.add(new User().setName("Andy").setAge(18));
        list.add(new User().setName("wang").setAge(20));
        userDao.insertBatch(list);
    }

}

6)测试

当调用 UserServiceinsertUserBatch() 方法时,就会触发批量插入,查看 SQL 输出日志:

JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2458318b] will not be managed by Spring
==>  Preparing: INSERT INTO user (name,age) VALUES (?,?) , (?,?)
==>  Parameters: Andy(String), 18(Integer), wang(String), 20(Integer)
<==  Updates: 2

可以看到,批量插入的 SQL 是真正意义上的批量插入。

注意: 查看 Mybatis-plusSQL 输出日志需要添加配置:

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

你可能感兴趣的:(Spring,mybatis-plus,批量插入)