当前位置: 首页 > article >正文

mybatis面试之批量插入

写在前面

本文看下通过mybatis如何来批量插入数据。

1:mybatis提供的数据插入方式

org.apache.ibatis.session.ExecutorType类中定义了执行器的种类,因为执行器就是来负责执行sql语句的,所以其也代表了mybatis所支持的数据插入的方式,源码如下:

org.apache.ibatis.session.ExecutorType
public enum ExecutorType {
  SIMPLE, REUSE, BATCH
}

其中SIMPLE就是默认的,即单条的更新。REUSE就是ReuseExecutor,根据sql语句缓存Statement。BATCH就是BatchExecutor,这种方式可以在一个事务中执行多个语句,然后批量发送给数据库,并提交事务。像这种:

start transaction;
update xxx;
insert xxx;
update yyy;
delete zzz;
commit;

JDBC对应代码如下:

String sql = "INSERT INTO saas_init_bakeups (" +
        "        delete_number, table_name, data, organ_sign,create_user)" +
        "        VALUES(?,?,?,?,?,?)";
DataSource dataSource = jdbcTemplate.getDataSource();
Connection connection = dataSource.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
List<Long> list = new ArrayList<>();
try {
    connection.setAutoCommit(false);
    ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
    for (InitBakeupsPo obj : bakeupsPoList) {
        ps.setString(1, obj.getDeleteNumber());
        ps.setString(2, obj.getTableName());
        ps.setBlob(3, string2Blob(obj.getData()));
        ps.setString(4, obj.getOrganSign());
        ps.setDate(5, date2Sql(obj.getCreateTime()));
        ps.setString(6, obj.getCreateUser());
        ps.addBatch();
    }
    ps.executeBatch();
    connection.commit();
    rs = ps.getGeneratedKeys(); //获取结果
    while (rs.next()) {
        list.add(rs.getLong(1));
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
    try {
        connection.close();
        ps.close();
        rs.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }

}

分别来看下。

2:SIMPLE使用foreach方式

可能配置如下:

<insert id="addEmps">
	insert into tbl_employee(<include refid="insertColumn"></include>) 
	values
	<foreach collection="emps" item="emp" separator=",">
		(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
	</foreach>
</insert>

但最终还是生成一个如下的sql语句:

insert into tbl_employee(
last_name,email,gender,d_id
) 
values
	(?,?,?,?)
 , 
	(?,?,?,?)

当foreach循环数据较多时,插入数的时长会增加比较多,可能如下图:
在这里插入图片描述

所以使用这种方式时,建议分批插入,每批不超过200条。

3:BATCH

打开session时需要指定参数ExecutorType.BATCH,代码可能如下:

public void test01() {
    //指定ExecutorType.BATCH创建sqlsession
	SqlSession openSession = build.openSession(ExecutorType.BATCH);
	UserDao mapper = openSession.getMapper(UserDao.class);
	longstart = System.currentTimeMillis();
	for(inti = 0; i < 1000000; i++) {
		String name = UUID.randomUUID().toString().substring(0, 5);
		mapper.addUser(newUser(null, name, 13));
	}
	openSession.commit();
	openSession.close();
	longend = System.currentTimeMillis();
	System.out.println("耗时时间:"+(end-start));
}

或

SqlSession session = sessionFactory.openSession(ExecutorType.BATCH);
for (Model model : list) {
    session.insert("insertStatement", model);
}
session.flushStatements();

如果有批量需求,建议使用这种方式。

4:Dynamic Sql

这是在Dynamic sql中提供的功能,需要额外引入如下pom:

<dependency>
    <groupId>org.mybatis.dynamic-sql</groupId>
    <artifactId>mybatis-dynamic-sql</artifactId>
    <version>1.1.4</version>
</dependency>

代码可能如下:

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
    TableMapper mapper = session.getMapper(TableMapper.class);
    //自定义你的方法来获取需要插入的数据
    List<TableRecord> records = getRecordsToInsert();
 	//BatchInsert
    BatchInsert<TableRecord> batchInsert = insert(records)
            .into(table)
            .map(id).toProperty("id")
            .map(field1).toProperty("field1")
            .map(field2).toProperty("field2")
            .build()
            .render(RenderingStrategy.MYBATIS3);
    batchInsert.insertStatements().stream().forEach(mapper::insert);
    session.commit();
} finally {
    session.close();
}

写在后面

参考文章列表

mybatis批量插入优化(ExecutorType.BATCH/BatchInsert/executeBatch) 。
MyBatis源码-解读Executor的三个实现类之ReuseExecutor(重用执行器) 。
MyBatis中批量操作foreach与BatchExecutor使用详解 。


http://www.kler.cn/a/6388.html

相关文章:

  • 【Web】2024“国城杯”网络安全挑战大赛决赛题解(全)
  • 【Object字段缺失】JS的对象在更新后发现Key值消失
  • EasyExcel停更,FastExcel接力
  • 深入解读数据资产化实践指南(2024年)
  • zabbix监控山石系列Hillstone监控模版(适用于zabbix7及以上)
  • 畅捷通T+13管理员密码任意重置漏洞
  • 串行通信协议---HART协议
  • 40. 组合总和 II
  • ChatGPT基础知识系列之Prompt
  • 4、网络编程——TCP相关的API及其实现的步骤
  • 为什么说标签限制了我们?放下标签,品生活中的美好
  • Agisoft Metashape 坐标系选择 坐标转换
  • Docker快速搭建SkyWalking[ OAP UI[登录] Elasticsearch]
  • 分享89个ASP影音娱乐源码,总有一款适合您
  • 【AI面试】BN(Batch Norm)批量归一化
  • 学习系统编程No.14【动静态库】
  • 计算机组成原理 --- 数据的表示和运算
  • 硬件工程师需要掌握的PCB设计常用知识点
  • 五分钟了解三门问题是什么?贝叶斯公式和蒙提霍尔问题有什么关联?
  • C/C++回调函数
  • C++ 每日一练
  • ChatGPT全球大封号!数10万企业停摆:第一批玩AI的人,被AI给玩了
  • Atomic包
  • 【数据结构】线性表(顺序存储和链式存储)两种方法,细节满满,保你学会
  • Compose(?/N) - 微件
  • 数据字典和数据字典视图