iBatisでは、insert時にシーケンスなどから採番し、insertしてから、その値を取得する
機能があります。その際に使用するのがselectKey要素です。
以下サンプルです。
[DDL]
-- vim: set ts=4 sw=4 et ws is nowrap ft=sql: CREATE TABLE SAMPLE009_TEST_TABLE( id int ,value1 varchar(100) ,primary key(id) ); CREATE SEQUENCE SAMPLE009_SEQ; -- -- サンプルデータ -- insert into SAMPLE009_TEST_TABLE values(SAMPLE009_SEQ.nextval, 'test value-001');
[データクラス]
// vim:set ts=4 sw=4 et ws is nowrap ft=java: package gsf.samples.ibatis.sample009; import java.io.*; import org.apache.commons.lang.builder.*; public class Sample009TestTable implements Serializable{ /** ID */ private Integer id; /** VALUE1 */ private String value1; /** * コンストラクタ.<br/> * */ public Sample009TestTable(){ // nop; } /** * Get id. * * @return id as Integer. */ public Integer getId(){ return this.id; } /** * Set id. * * @param id the value to set. */ protected void setId(Integer id){ this.id = id; } /** * Get value1. * * @return value1 as String. */ public String getValue1(){ return this.value1; } /** * Set value1. * * @param value1 the value to set. */ public void setValue1(String value1){ this.value1 = value1; } @Override public String toString(){ return new ReflectionToStringBuilder(this).toString(); } }
[SQLマッピング設定ファイル]
<?xml version="1.0" encoding="Windows-31J"?> <!-- vim:set ts=4 sw=4 et ws is nowrap ft=xml: --> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap namespace="SelectKey"> <typeAlias alias="Sample009TestTable" type="gsf.samples.ibatis.sample009.Sample009TestTable"/> <sql id="insertSample009TestTable"> insert into SAMPLE009_TEST_TABLE (id, value1) values (#id#, #value1#) </sql> <select id="getMaxNumberSample009TestTable" resultClass="int"> select max(id) from SAMPLE009_TEST_TABLE </select> <insert id="insertSample009TestTableNoAutoKey" parameterClass="Sample009TestTable"> <include refid="insertSample009TestTable"/> </insert> <insert id="insertSample009TestTableWithAutoKey" parameterClass="Sample009TestTable"> <selectKey resultClass="int" type="pre" keyProperty="id"> select SAMPLE009_SEQ.nextval as id from dual </selectKey> <include refid="insertSample009TestTable"/> </insert> </sqlMap>
[動作確認クラス]
// vim:set ts=4 sw=4 et ws is nowrap ft=java: package gsf.samples.ibatis.sample009; import java.sql.*; import gsf.interfaces.sqlmap.*; import gsf.utils.sqlmap.*; import com.ibatis.sqlmap.client.*; public class IBatisSample009{ private static class MaxIdNumberExecutor implements SqlMapClientExecutor{ public Object execute(SqlMapClient sqlMap) throws SQLException{ return sqlMap.queryForObject("getMaxNumberSample009TestTable"); } } private static class InsertSampleWithAutoKeyExecutor implements SqlMapClientExecutor{ private Sample009TestTable data; public void setData(Sample009TestTable data){ this.data = data; } public Object execute(SqlMapClient sqlMap) throws SQLException{ return sqlMap.insert("insertSample009TestTableWithAutoKey", data); } } private static class InsertSampleNoAutoKeyExecutor implements SqlMapClientExecutor{ private Sample009TestTable data; public void setData(Sample009TestTable data){ this.data = data; } public Object execute(SqlMapClient sqlMap) throws SQLException{ return sqlMap.insert("insertSample009TestTableNoAutoKey", data); } } public static void main(String[] args){ Sample009TestTable data = new Sample009TestTable(); // // 自動採番を利用した例 // System.out.println("=========== 自動採番の例 Start ==============="); data.setValue1("自動採番を利用。"); InsertSampleWithAutoKeyExecutor executor = new InsertSampleWithAutoKeyExecutor(); executor.setData(data); System.out.printf("実行する前のデータオブジェクト:%s\n", data); ////////////////////////////////////////////////////////////////////////// // insertにて、内部でselectKeyを使用した場合、sqlMap.insert()の戻り値は // 採番されたキーの値が戻り値として返却される. // Integer newKey = (Integer) SqlMapUtils.executeWithTransaction(executor); System.out.printf("採番されたキー:%s\n", newKey); System.out.printf("実行した後のデータオブジェクト:%s\n", data); System.out.println("=========== 自動採番の例 end ==============="); System.out.printf("\n\n"); // // 自動採番を利用しない例 // System.out.println("=========== 手動採番の例 Start ==============="); Integer nextNumber = (Integer) SqlMapUtils.executeNoTransaction(new MaxIdNumberExecutor()); data.setId(++nextNumber + 100000); data.setValue1("手動採番を利用。"); InsertSampleNoAutoKeyExecutor executor2 = new InsertSampleNoAutoKeyExecutor(); executor2.setData(data); System.out.printf("実行する前のデータオブジェクト:%s\n", data); ////////////////////////////////////////////////////////////////////////// // insertにて、内部でselectKeyを使用していない場合、sqlMap.insert()の戻り値は // nullとなる. // Object result = SqlMapUtils.executeWithTransaction(executor2); System.out.printf("insertメソッドの戻り値:%s\n", result); System.out.printf("実行した後のデータオブジェクト:%s\n", data); System.out.println("=========== 手動採番の例 end ==============="); } }
実行すると、selectKeyを使用して、insertを行っている場合は、採番された値が
帰ってきていることがわかります。selectKeyを使用していない場合の戻り値はnullです。
selectKey要素は、以下の属性を持っています。
- resultClass
- type
- keyProperty
resultClassはそのまま、いつもどおりです。
typeは、preとpostが指定できます。preはinsertを行う前に実行され、
postは、insertを行った後に実行されます。SQL Serverなどは、postに
しないとうまく動きません。通常は、preを指定するのが多いでしょう。
最後のkeyPropertyですが、これは、採番して取得した値を
parameterClassで指定されたオブジェクトのどのプロパティにセットするかを
指定するものです。上記の場合ですと、Sample009TestTableのidプロパティに
採番された値がセットされます。ちなみに、keyPropertyを指定しない場合は、
iBatisの方で勝手に判断して、採番するのに実行したSQLの結果カラムから
適合するプロパティを探し出しセットしてくれます。
つまり、insertメソッドの結果でも取得キーが帰ってきますが、
パラメータで渡したオブジェクトにもセットされるということになります。
ちなみに、上記のサンプルを実行した結果は、たとえば以下のようになります。
exec: [java] =========== 自動採番の例 Start =============== [java] 実行する前のデータオブジェクト:gsf.samples.ibatis.sample009.Sample009TestTable@de6f34[id=<null>,value1=自動採番を利用。] [java] 採番されたキー:11 [java] 実行した後のデータオブジェクト:gsf.samples.ibatis.sample009.Sample009TestTable@de6f34[id=11,value1=自動採番を利用。] [java] =========== 自動採番の例 end =============== [java] =========== 手動採番の例 Start =============== [java] 実行する前のデータオブジェクト:gsf.samples.ibatis.sample009.Sample009TestTable@de6f34[id=300012,value1=手動採番を利用。] [java] insertメソッドの戻り値:null [java] 実行した後のデータオブジェクト:gsf.samples.ibatis.sample009.Sample009TestTable@de6f34[id=300012,value1=手動採番を利用。] [java] =========== 手動採番の例 end ===============