Oracle 不支持 MySQL 的 VALUES (...), (...), ... 多行插入語法。MyBatis 批量插入 Oracle 的標準做法是:INSERT INTO ... SELECT ... FROM DUAL UNION ALL SELECT ... FROM DUAL。本文給出完整工程示例,含實體、Mapper、XML、測試代碼。
CREATE TABLE ACCOUNT_INFO (
ID NUMBER(12) NOT NULL,
USERNAME VARCHAR2(64),
PASSWORD VARCHAR2(64),
GENDER CHAR(1),
EMAIL VARCHAR2(64),
CREATE_DATE DATE
);
public class AccountInfo {
private Long id;
private String userName, password, gender, email;
private Date createDate;
// getter/setter/toString
}
public interface AccountInfoMapper {
List queryAllAccountInfo();
int batchInsertAccountInfo(List accountInfoList);
}
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="username" value="xxx"/>
<property name="password" value="xxx"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="config/AccountInfoMapper.xml"/>
</mappers>
</configuration>
<mapper namespace="com.oracle.mapper.AccountInfoMapper">
<resultMap id="BaseResultMap" type="com.oracle.entity.AccountInfo">
<id column="ID" property="id" jdbcType="DECIMAL"/>
<result column="USERNAME" property="userName" jdbcType="VARCHAR"/>
<result column="PASSWORD" property="password" jdbcType="VARCHAR"/>
<result column="GENDER" property="gender" jdbcType="CHAR"/>
<result column="EMAIL" property="email" jdbcType="VARCHAR"/>
<result column="CREATE_DATE" property="createDate" jdbcType="DATE"/>
</resultMap>
<select id="queryAllAccountInfo" resultMap="BaseResultMap">
SELECT ID, USERNAME, PASSWORD, GENDER, EMAIL, CREATE_DATE FROM ACCOUNT_INFO
</select>
<insert id="batchInsertAccountInfo" parameterType="java.util.List">
INSERT INTO ACCOUNT_INFO (ID, USERNAME, PASSWORD, GENDER, EMAIL, CREATE_DATE)
(
<foreach collection="list" item="accountInfo" separator="UNION ALL">
SELECT #{accountInfo.id}, #{accountInfo.userName}, #{accountInfo.password},
#{accountInfo.gender}, #{accountInfo.email}, #{accountInfo.createDate}
FROM DUAL
</foreach>
)
</insert>
</mapper>
關鍵點:
collection="list":MyBatis 自動將 List 參數包裝為 {list: [...]}。separator="UNION ALL":生成 SELECT ... FROM DUAL UNION ALL SELECT ... FROM DUAL。SELECT ... FROM DUAL 是 Oracle 單行插入標準寫法。public class MybatisTest {
public static void main(String[] args) throws Exception {
SqlSessionFactory sf = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("config/mybatis-configuration.xml"));
try (SqlSession session = sf.openSession()) {
AccountInfoMapper mapper = session.getMapper(AccountInfoMapper.class);
List data = generateData(); // 構造 3 條測試數據
int rows = mapper.batchInsertAccountInfo(data);
System.out.println("批量插入行數: " + rows);
session.commit();
}
}
static List generateData() { ... }
}
| 場景 | 方案 |
|---|---|
| 數據量 < 1000 | 單次 UNION ALL 即可,SQL 長度可控 |
| 數據量 1000-10000 | 分批提交(如 500 條/批),避免 SQL 過長超過 Oracle 64KB 限制 |
| 數據量 > 10000 | 1. 臨時表 + INSERT /*+ APPEND */ 直寫數據塊 2. SQL*Loader / 外部表 3. Oracle 批量綁定 PreparedStatement.addBatch() 繞過 MyBatis |
java.sql.Date 對應 Oracle DATE,java.util.Date/LocalDateTime 需配置類型處理器。SEQ.NEXTVAL 在 SQL 中賦值。session.commit() 統一提交。#{accountInfo.id} 中的 accountInfo 必須與 foreach item="accountInfo" 一致。MyBatis foreach + UNION ALL 是 Oracle 批量插入的標準模式,代碼簡潔、類型安全、易維護。大數據量場景分批提交或轉用臨時表/直路徑載入,根據業務量級選擇最優方案。