Mybatis-Plus批量插入应该怎么用(下)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: Mybatis-Plus批量插入应该怎么用

再往下

1673457045181.jpg

这里就是真正执行的方法了,idxLimit会对比DEFAULT_BATCH_SIZE和集合长度两个数中的最小数,作为批量大小,也就是说当集合长度不够1000,那么执行的时候批量大小就是集合的长度,就执行一次。


for循环中的consumer:对应的类型是一个函数式接口,代表一个接受两个输入参数且不返回任何内容的操作符。意思是给定两个参数sqlSession、循环中当前element对象,执行一次传递过来的consumer匿名函数。也就是上边源码里的插入匿名函数。

1673457053214.jpg

当i == indLimit时:执行一次预插入,并重新计算idxLimit的值


if中idxLimit计算规则:当前idxLimit加batchSize(默认1000) 和 集合长度 取最小值,计算出来的结果肯定不会超过集合的长度,最后的批次时idxLimit等于集合的长度,将这个值作为下一次执行预插入的时间点。


sqlSession.flushStatements():当有处于事务中的时候,起到一种预插入的作用,执行了这行代码之后,要插入的数据会锁定数据库的一行记录,并把数据库默认返回的主键赋值给插入的对象,这样就可以把该对象的主键赋值给其他需要的对象中去了,这里不是事务提交啊。


最后方法执行完后@Transactional注解会默认提交事务,如果调用的方法上还有@Transactional注解,默认的事务传播类型是Propagation.REQUIRED,不会新开启事务,如果没有@Transactional注解才会新开起事务

详细介绍请看Spring @Transactional事务管理


3. insert循环插入


把数据库中的数据清空,还原到空表状态

@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {
    @Override
    public void insertList() {
        List<Users> list = new ArrayList<>();
        for (int i = 0; i < 5000; i++) {
            Users users = new Users();
            users.setUserName("yy" + i);
            users.setAge(18);
            users.setEmail("123@qq.com");
            users.setAddress("临汾" + i);
            users.setAccount("1" + i);
            users.setPassword("pw" + i);
            list.add(users);
        }
        long start = System.currentTimeMillis();
        for (int i = 0; i < list.size(); i++) {
            baseMapper.insert(list.get(i));
        }
        long end = System.currentTimeMillis();
        System.out.println("5000条数据插入,耗时:" + (end - start));
    }
}

1673457083415.jpg

5000条数据每条都是一个单独的事务。就是一条条插入,成功失败都不会互相影响

耗时:161.2秒


4. 自定义sql插入


UsersMapper.xml

<insert id="insertList">
        insert into users(user_name, age, email, address, account, password) values
        <foreach collection="list" item="it" separator=",">
            (#{it.userName}, #{it.age}, #{it.email}, #{it.address}, #{it.account}, #{it.password})
        </foreach>
    </insert>


UsersMapper

void insertList(@Param("list") List<Users> list);
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {
    @Override
    public void insertList() {
        List<Users> list = new ArrayList<>();
        for (int i = 0; i < 5000; i++) {
            Users users = new Users();
            users.setUserName("yy" + i);
            users.setAge(18);
            users.setEmail("123@qq.com");
            users.setAddress("临汾" + i);
            users.setAccount("1" + i);
            users.setPassword("pw" + i);
            list.add(users);
        }
        long start = System.currentTimeMillis();
        baseMapper.insertList(list);
        long end = System.currentTimeMillis();
        System.out.println("5000条数据插入,耗时:" + (end - start));
    }
}

1673457110364.jpg

这里是把要插入的数据拼接在一个insert语句后面执行

INSERT INTO users (user_name,age,email,address,account,password) 
VALUES (?,?,?,?,?,?) , (?,?,?,?,?,?) , (?,?,?,?,?,?).....


这种效率是最高的,但是这种需要我们在每个批量插入对应的xml中取写sql语句,有点不太符合现在提倡的免sql开发,下面介绍一下它的升级版


5. insertBatchSomeColumn


mybatis-plus提供了InsertBatchSomeColumn批量insert方法。通过SQL 自动注入器接口 ISqlInjector注入通用方法 SQL 语句 然后继承 BaseMapper 添加自定义方法,全局配置 sqlInjector 注入 MP 会自动将类所有方法注入到 mybatis 容器中。我们需要通过这种方式注入下。


MySqlInjector.java

/**
 * 自定义Sql注入
 * @author:  yh
 * @date:  2022/8/30
 */
public class MySqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        //增加自定义方法,字段注解上不等于FieldFill.DEFAULT的字段才会插入
        methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.DEFAULT));
        return methodList;
    }
}


MybatisPlusConfig.java

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MySqlInjector sqlInjector() {
        return new MySqlInjector();
    }
}


自定义MyBaseMapper

public interface MyBaseMapper <T> extends BaseMapper<T> {
    int insertBatchSomeColumn(List<T> entityList);
}


mapper继承的这里也改下

public interface UsersMapper extends MyBaseMapper<Users> {
}


插入的时候过滤字段,需要配置属性

@Data
public class Users extends Model<Users> {
    /**
     * id
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    // 插入的时候过滤这个字段,默认值就是FieldFill.DEFAULT
    @TableField(fill = FieldFill.DEFAULT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT)
    private String userName;
    @TableField(fill = FieldFill.INSERT)
    private Integer age;
    @TableField(fill = FieldFill.INSERT)
    private String email;
    @TableField(fill = FieldFill.INSERT)
    private String address;
    @TableField(fill = FieldFill.INSERT)
    private String account;
    @TableField(fill = FieldFill.INSERT)
    private String password;
}


修改一下service调用

@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Override
    public void insertList() {
        List<Users> list = new ArrayList<>();
        for (int i = 0; i < 5000; i++) {
            Users users = new Users();
            users.setUserName("yy" + i);
            users.setAge(18);
            users.setEmail("123@qq.com");
            users.setAddress("临汾" + i);
            users.setAccount("1" + i);
            users.setPassword("pw" + i);
            list.add(users);
        }
        long start = System.currentTimeMillis();
        baseMapper.insertBatchSomeColumn(list);
        long end = System.currentTimeMillis();
        System.out.println("5000条数据插入,耗时:" + (end - start));
    }
}


运行结果:

1673457215422.jpg

createTime字段被过滤掉了

1673457224139.jpg

1673457230164.jpg

执行时间和上边自定义sql一样,在1秒内浮动,如果量太大几十万条建议多线程分批处理。Java 多线程分批同步数据

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
SQL XML 关系型数据库
Mybatis-Plus通过SQL注入器实现真正的批量插入
Mybatis-Plus通过SQL注入器实现真正的批量插入
2716 0
Mybatis-Plus通过SQL注入器实现真正的批量插入
|
2月前
|
SQL 存储 Kubernetes
Seata常见问题之mybatisplus的批量插入方法报SQL错误如何解决
Seata 是一个开源的分布式事务解决方案,旨在提供高效且简单的事务协调机制,以解决微服务架构下跨服务调用(分布式场景)的一致性问题。以下是Seata常见问题的一个合集
43 0
|
4月前
|
存储 Java 数据库连接
MyBatis Plus中的批量插入:通过开启rewriteBatchedStatements=true
MyBatis Plus中的批量插入:通过开启rewriteBatchedStatements=true
147 0
|
5月前
|
Java 数据库连接 mybatis
mybatis 批量插入
mybatis 批量插入
26 0
|
10月前
|
SQL Java 数据库连接
MyBatis痛点验证,使用 foreach 批量插入慢?
MyBatis痛点验证,使用 foreach 批量插入慢?
180 0
|
10月前
|
SQL Java 数据库连接
如何使用Mybatis实现批量插入 ?
如何使用Mybatis实现批量插入 ?
49 0
|
11月前
|
小程序 Java 数据库连接
【实践】mybatis批量插入map
【实践】mybatis批量插入map
472 0
|
SQL 缓存 Oracle
MyBatis 批量插入别再乱用 foreach 了,5000 条数据花了 14 分钟。。。
MyBatis 批量插入别再乱用 foreach 了,5000 条数据花了 14 分钟。。。
|
SQL 消息中间件 JavaScript
求求你们了,MyBatis 批量插入别再乱用 foreach 了,5000 条数据花了 14 分钟。。
求求你们了,MyBatis 批量插入别再乱用 foreach 了,5000 条数据花了 14 分钟。。
|
SQL Java 数据库连接
mybatis 批量插入 Column count doesn‘t match value count at row 1
mybatis 批量插入 Column count doesn‘t match value count at row 1
120 0