Basic environment
Language: Java 8 Database: Oracle ORM Framework: MyBatis 3.4.5
demand
Insert data in batches. The data must have an self-increasing ID. Each insert is marked with a unique sessionId, which is returned when the insert is complete.
plan
Cyclic insert single record, pseudocode:
int sessionId = dao.querySessionId();
for (Record record : recordList) {
dao.insertRecord(record, sessionId);
}
return sessionId;
Copy the code
The above solution is straightforward, but each INSERT operation in the loop interacts with the DB once, and when there is a large amount of data, it can take a lot of time to transfer over the network, causing performance problems.
To improve the
Problems can be remedied by bulk inserts.
Batch insert with autoincrement ID
A common batch insert template in Oracle is:
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;Copy the code
However, each record needs to have an increment id. Oracle uses Sequence to implement this, so it is easy to think of the following way:
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;
Copy the code
Unfortunately, this is not possible because all sequence.nextval will be the same value, causing primary key conflicts.
Then try something else. Oracle supports batch fetching of data from one table into another:
INSERT INTO target_table (col1, col2, col3)
SELECT col1,
col2,
col3
FROM source_table
WHERE condition;
Copy the code
In this way, we can construct a subtable of the inserted data with UNION ALL (source_table above) to implement batch inserts. The advantage over INSERT ALL INTO is that you can use the auto-increment of the 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...). ;Copy the code
MyBatis dynamic SQL to achieve roughly as follows:
<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>
Copy the code
Return the sessionId after the insert is complete
In Mybatis, a SelectKey can be used to return a property. A SelectKey is a sublabel of an Insert. It is implemented by performing a subquery of the SelectKey before the Insert statement is executed. The results of the subquery can be assigned to the query parameters, for example
public class Foo {
private int id;
private String col2;
private String col3;
}
public interface FooDao {
void sampleInsert(Foo foo);
}
Copy the code
<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>
Copy the code
When the insert is complete, the argument foo.id is the self-increment of the SESSION_SEQUENCE (note that you cannot annotate the argument with @param () in the Dao).
However, this method only supports single record inserts, and Oracle batch inserts cannot complete the assignment. So there are only two steps to do this:
- To obtain
sessionId
(SESSION_SEQUENCE.NEXTVAL
) - Bulk insert tape
sessionId
The record of
or
- withSelectKeyTo select the
sessionId
(SESSION_SEQUENCE.NEXTVAL
) and batch insert records - To obtain
sessionId
(SESSION_SEQUENCE.CURRVAL
)
Note that in the second method, you need to ensure that the two methods are in the same Transaction, otherwise the values of the Sequence will be inconsistent.
conclusion
This article briefly summarizes the MyBatis to Oracle batch insert data method, for a quick note.
Reference
The Ultimate Guide to Oracle INSERT ALL Statement Oracle INSERT INTO SELECT Inserting Multiple Rows Using a Single Statement
Inserting multiple rows with sequence in Oracle