大量のInsertなどが発行される場合、普通にひとつずつ発行していると
時間がかかってしまいます。そのようなときは、バッチ処理を行い
一括して処理を送信します。
iBatisにおいて、バッチ処理を行う場合、
以下のメソッドを使用します。
- sqlMap.startBatch()
- sqlMap.executeBatch()
startBatch()とexecuteBatch()の間でSQLを発行します。
以下、サンプルです。
[テーブル定義]
CREATE TABLE BIG_DATA_TABLE( id int ,val1 varchar(1000) ,val2 varchar(2000) ,val3 varchar(3000) );
[テーブル対応クラス]
// vim:set ts=4 sw=4 et ws is nowrap ft=java fenc=cp932 ff=dos: package gsf.samples.ibatis.sample005; /** * BIG_DATA_TABLEテーブルに対応するドメインオブジェクト.<br/> * * @author gsf_zero1 * */ public class BigData{ /** ID */ private Integer id; /** VAL1 */ private String val1; /** VAL2 */ private String val2; /** VAL3 */ private String val3; /** * Get id. * * @return id as Integer. */ public Integer getId(){ return this.id; } /** * Set id. * * @param id the value to set. */ public void setId(Integer id){ this.id = id; } /** * Get val1. * * @return val1 as String. */ public String getVal1(){ return this.val1; } /** * Set val1. * * @param val1 the value to set. */ public void setVal1(String val1){ this.val1 = val1; } /** * Get val2. * * @return val2 as String. */ public String getVal2(){ return this.val2; } /** * Set val2. * * @param val2 the value to set. */ public void setVal2(String val2){ this.val2 = val2; } /** * Get val3. * * @return val3 as String. */ public String getVal3(){ return this.val3; } /** * Set val3. * * @param val3 the value to set. */ public void setVal3(String val3){ this.val3 = val3; } }
[SQL設定ファイル]
<?xml version="1.0" encoding="Windows-31J"?> <!-- vim:set ts=4 sw=4 et ws is nowrap ft=xml fenc=cp932 ff=dos: --> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="BatchSamples"> <typeAlias alias="BigData" type="gsf.samples.ibatis.sample005.BigData"/> <select id="countBigData" resultClass="int"> select count(id) from BIG_DATA_TABLE </select> <insert id="insertBigData" parameterClass="BigData"> insert into BIG_DATA_TABLE (id, val1, val2, val3) values (#id#, #val1#, #val2#, #val3#) </insert> <delete id="allDeleteBigData"> delete from BIG_DATA_TABLE </delete> </sqlMap>
[サンプルクラス]
// vim:set ts=4 sw=4 et ws is nowrap ft=java fenc=cp932 ff=dos: package gsf.samples.ibatis.sample005; import java.util.*; import org.apache.commons.lang.time.*; import com.ibatis.common.resources.*; import com.ibatis.sqlmap.client.*; /** * Sample005の動作を確認するクラス.<br/> * * @author gsf_zero1 * */ public class IBatisSample005{ public static void main(String[] args) throws Exception{ SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient( Resources.getResourceAsReader("SqlMapConfig.xml")); try{ sqlMap.startTransaction(); sqlMap.delete("allDeleteBigData", null); sqlMap.commitTransaction(); }finally{ sqlMap.endTransaction(); } System.out.printf("BIG_DATA_TABLEの全データを削除......\n\n"); // // 普通にinsertを60000件行う. // StopWatch stopWatch = new StopWatch(); try{ stopWatch.start(); sqlMap.startTransaction(); for(int i = 0; i < 60000; i++){ BigData b = new BigData(); b.setId*1; b.setVal1(String.format("%s-%d", "val1", (i + 1))); b.setVal2(String.format("%s-%d", "val2", (i + 1))); b.setVal3(String.format("%s-%d", "val3", (i + 1))); sqlMap.insert("insertBigData", b); } sqlMap.commitTransaction(); stopWatch.stop(); }finally{ sqlMap.endTransaction(); } System.out.printf("普通にInsert:%s\n\n", stopWatch); // // バッチ処理にて60000件Insert。 // stopWatch = new StopWatch(); try{ stopWatch.start(); sqlMap.startTransaction(); // // バッチ処理開始. // sqlMap.startBatch(); for(int i = 120000; i > 60000; i--){ BigData b = new BigData(); b.setId*2; b.setVal1(String.format("%s-%d", "val1", (i + 1))); b.setVal2(String.format("%s-%d", "val2", (i + 1))); b.setVal3(String.format("%s-%d", "val3", (i + 1))); sqlMap.insert("insertBigData", b); } // // バッチ実行. // sqlMap.executeBatch(); sqlMap.commitTransaction(); stopWatch.stop(); }finally{ sqlMap.endTransaction(); } System.out.printf("バッチ処理でInsert:%s\n\n", stopWatch); System.out.printf("Insert件数:%d\n", (Integer) sqlMap.queryForObject("countBigData", null)); } }
後は、iBatis設定ファイルにSQL設定ファイルを定義します。
<sqlMap resource="gsf/samples/ibatis/sample005/Batch.ibatis.xml"/>
ローカルにて、H2 DatabaseをTCPモードでスタートさせて試してみましたが、大体以下のような結果になりました。
おおよそ、半分の時間ってところですね。
他の環境では、こうならないかもしれませんが。
exec: [java] BIG_DATA_TABLEの全データを削除...... [java] 普通にInsert:0:00:27.219 [java] バッチ処理でInsert:0:00:12.360 [java] Insert件数:120000
ちなみに、H2 Databaseを組み込みモードで試すと、以下のようになりました。
exec: [java] BIG_DATA_TABLEの全データを削除...... [java] 普通にInsert:0:00:08.031 [java] バッチ処理でInsert:0:00:05.360 [java] Insert件数:120000