Mybatis批量插入Oracle数据的方法实例

 更新时间:2022年01月07日 14:52:48   作者:night_field  
在开发中或多或少都会遇到数据批量插入的功能,最近我在做项目的过程中就遇到了这样一个问题,下面这篇文章主要给大家介绍了关于Mybatis批量插入Oracle数据的相关资料,需要的朋友可以参考下

基本环境

语言:Java 8 数据库:Oracle ORM 框架:MyBatis 3.4.5

需求

批量插入数据,数据需要有自增 id。每次插入有一个唯一的 sessionId 来标记这些记录,插入完成之后返回这个 sessionId。

方案

循环插入单条记录,伪代码:

int sessionId = dao.querySessionId();
for (Record record : recordList) {
    dao.insertRecord(record, sessionId);
}
return sessionId;

上述解决方案很简明易懂,但是循环中每次 insert 操作都会与 DB 交互一次,当数据量很大时,会花费很多时间在网络传输上,导致性能问题。

改进

问题可以通过批量插入来改善。

带自增 id 的批量插入

Oracle 中比较常见的批量插入模版是:

INSERT ALL
   INTO target_table (col1, col2, col3) VALUES ('id1_1', 'val1_2', 'val1_3')
   INTO target_table (col1, col2, col3) VALUES ('id2_1', 'val2_2', 'val2_3')
   ...
Subquery;

但是每条记录都需要有一个自增 id,Oracle 中一般用 Sequence 来实现,于是比较容易想到的是用下面这种方式:

INSERT ALL
   INTO table (col1, col2, col3) VALUES (SEQUENCE.NEXTVAL, 'val1_2', 'val1_3')
   INTO table (col1, col2, col3) VALUES (SEQUENCE.NEXTVAL, 'val2_2', 'val2_3')
   ...
SELECT 1 FROM DUAL;

不过遗憾的是,上述方案行不通,因为所有的 SEQUENCE.NEXTVAL 都会是同一个值,会产生主键冲突。

接着尝试其他的方案。Oracle 支持从一个表里批量选取数据插入另一个表中:

INSERT INTO target_table (col1, col2, col3)
SELECT col1,
       col2,
       col3
FROM source_table
WHERE condition;

用上述方式,我们可以把被插入的数据用 UNION ALL 构造一个子表,也就是上面的 source_table 来实现批量插入。跟 INSERT ALL INTO 相比的好处是,可以使用 Sequence 的自增值:

INSERT INTO target_table (col1, col2, col3)
SELECT SEQUENCE.NEXTVAL,
       col2,
       col3
FROM (
    SELECT 'val1_2' col2, 'val1_3' col3 FROM dual UNION ALL
    SELECT 'val2_2' col2, 'val2_3' col3 FROM dual UNION ALL
    ...
);

MyBatisdynamic sql 来实现大致如下:

<insert id="sampleInsert" parameterType="java.util.List">
    INSERT INTO target_table (col1, col2, col3)
    SELECT SEQUENCE.NEXTVAL,, col2, col3 FROM
    <foreach collection="list" item="item" index="index" open="(" close=")" separator=" UNION ALL ">
        SELECT #{item.val2} col2, #{item.val2} col3 FROM dual
    </foreach>
</insert>

插入完成之后返回 sessionId

Mybatis 中,返回某个 property 可以用 SelectKey。SelectKey 是 Insert 的子标签,实现原理是在执行插入语句之前先做一次 SelectKey 的子查询,此处,可以将子查询的结果赋值到查询的参数当中,例如

public class Foo {
    private int id;
    private String col2;
    private String col3;
}
public interface FooDao {
    void sampleInsert(Foo foo);
}
<insert id="sampleInsert" useGeneratedKeys="true" parameterType="Foo" keyProperty="id">
    <selectKey keyProperty="id" order="BEFORE" resultType="int">
        SELECT SESSION_SEQUENCE.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO target_table (col1, col2, col3)
    VALUES (#{id}, #{col2}, #{col3})
</insert>

当插入结束之后,参数 foo.id 就会是 SESSION_SEQUENCE 的自增值(注意在 Dao 中不能用 @Param() 标注参数)。

然而这种方式只支持单条记录的插入,Oracle 中批量插入的情况就无法完成赋值了。所以此处只能分成两步来做:

  • 获取 sessionId(SESSION_SEQUENCE.NEXTVAL)
  • 批量插入带 sessionId 的记录

或者

  • 用 SelectKey 选出 sessionId(SESSION_SEQUENCE.NEXTVAL)并批量插入记录
  • 获取 sessionId(SESSION_SEQUENCE.CURRVAL)

注意上述第二种方式,需要保证两个方法在同一个 Transaction 里面,否则 Sequence 的值会不一致。

注意事项

oracle中用insert into xxx values (xxx,xxx),(xxx,xxx) 这种语法应该通不过的,会报错,ORA-00933: SQL 命令未正确结束,要用这种

insert into  t_test (id, prop_name)   
select 1,'aaa' from dual union all    
select 2,'bbb' from dual union all  
select 3,'ccc' from dual;

总结

本文简单总结了在 MyBatis 中往 Oracle 批量插入数据的方法,作一个快速笔记。

到此这篇关于Mybatis批量插入Oracle数据的文章就介绍到这了,更多相关Mybatis批量插入Oracle内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

Reference

相关文章

  • Java SSM整合开发统一结果封装详解

    Java SSM整合开发统一结果封装详解

    这篇文章主要介绍了Java SSM整合开发实现统一结果封装,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Java系统变量参数获取设置System.getProperties()的方法

    Java系统变量参数获取设置System.getProperties()的方法

    这篇文章主要介绍了Java系统变量参数System.getProperties()获取设置方法,文末给大家提到了Systm.getenv()与System.getProperties()区别,需要的朋友可以参考下
    2022-01-01
  • logback TimeBasedRollingPolicy按天生成日志源码解析

    logback TimeBasedRollingPolicy按天生成日志源码解析

    这篇文章主要为大家介绍了logback TimeBasedRollingPolicy按天生成日志源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • 深入Java冒泡排序与选择排序的区别详解

    深入Java冒泡排序与选择排序的区别详解

    本篇文章是对Java冒泡排序与选择排序的区别进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 编写调用新浪微博API的Java程序来发送微博

    编写调用新浪微博API的Java程序来发送微博

    这篇文章主要介绍了编写调用新浪微博API的Java程序来发送微博的方法,只是展示了一个基本的程序框架而非一个完整的图形化软件:)需要的朋友可以参考下
    2015-11-11
  • 深入解析Java的设计模式编程中建造者模式的运用

    深入解析Java的设计模式编程中建造者模式的运用

    这篇文章主要介绍了深入解析Java的设计模式编程中建造者模式的运用,同时文中也介绍了建造者模式与工厂模式的区别,需要的朋友可以参考下
    2016-02-02
  • Spring Boot(二)之web综合开发

    Spring Boot(二)之web综合开发

    本篇文章为大家介绍spring boot的其它特性(有些未必是spring boot体系桟的功能,但是是spring特别推荐的一些开源技术本文也会介绍),对了这里只是一个大概的介绍,特别详细的使用我们会在其它的文章中来展开说明
    2017-05-05
  • Spring Security登录表单配置示例详解

    Spring Security登录表单配置示例详解

    这篇文章主要介绍了Spring Security登录表单配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • 利用Java编写一个属于自己的日历

    利用Java编写一个属于自己的日历

    这篇文章主要为大家介绍了如何利用Java编写一个属于自己的日历,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起尝试一下
    2022-05-05
  • JPA-JpaRepository方法命名语法说明

    JPA-JpaRepository方法命名语法说明

    这篇文章主要介绍了JPA-JpaRepository方法命名语法说明,具有很好的参考价值。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11

最新评论