oracle+mybatis批量插入的两种常规写法

    技术2022-07-10  117

    需求

    示例:很普通的需求

    表结构:

    create table t_user( user_id varchar2(20), user_name varchar2(20) );

    java bean:

    public class User { String userId; String userName; // ... }

    现在有一个List<User>对象插入到t_user表里,oracle数据库,mybatis框架,使用批量插入方式。

    实现

    写法不固定,我这样写的,仅作参考

    多表插入

    <insert id="batchSave" parameterType="com.xuxd.bean.User"> insert all <foreach collection="list" item="user" separator=" " open=" " close=" " index="index"> into t_user( user_id, user_name ) VALUES ( #{user.userId}, #{user.userName} ) </foreach> select 1 from dual </insert>

    单表插入

    <insert id="batchSave" parameterType="com.xuxd.bean.User"> insert into t_user(user_id, user_name) select u.id, u.name from ( <foreach collection="list" index="index" item="user" open=" " close=" " separator=" union all "> select #{user.userId} as id, #{user.userName} as name from dual </foreach> ) u </insert>

    说明

    这两种写法很常见(细节上可能不同),在网上一搜就出来了,大多类似,对于初学者可能好奇为何这样写,解释下。

    下面参考了官方文档,SQL Language Reference11g Release 2 (11.2)

    看下插入语法:

    单表插入和多表插入,按前面的顺序解释

    多表插入

    根据当前场景主要是上面红框内,无条件多表插入。

    insert all into t1(...) values (...) into t2(...) values(...) ... select ... from t

    意思是向t1、t2...等多个表中插入数据,后面注意跟了个子查询select ... from t。这个子查询的结果前面是可以用的。but,重点是这个子查询的结果行数用来计算前面插入的每个表的行数。所以,如果子查询返回多行,前面每个表就会插入多行,对于返回的每一行,每个表都要执行一次插入。如果是0行,前面每个表都不会插入。

    因此,当前场景的mybatis写法实现是,插入的多个表都是同一个表,然后select 1 from dual返回的行数是1,每个表就只插入1行。

    顺便提一下,如果需要每行id是一个序列生成的,这种情况,就不能这样写了,因为这条语句,会被看做一条sql,所以如果需要生成序列,那么每列的序列值都是同一个值。

    单表插入

    单表插入,这里实现其实就是一个子查询,查询是借用dual表返回结果,可以看下子查询语法:

    每一个子查询:select #{user.userId} as id #{user.userName} as name from dual使用union all,这样就很清楚了。

    Processed: 0.010, SQL: 9