マッパークラスは、SQLマッパーを定義する時に指定しますが、どのマッパークラスを指定するかによりデータベースアクセス時の振る舞いが変わってきます。
Webtribeではいくつかのマッパークラスを標準で提供していますが、次のように、標準のマッパークラスでは実現できない処理を行う必要がある場合には、要件に応じたマッパークラスを作成し、プロジェクトに登録して使うことができます。
マッパークラスを作成するために必要なものは、次の通りです。
ここでは例として、テーブルから全レコードを削除するマッパークラスのコーディングについて説明します。
全レコードを削除するだけですので、入力アイテム、出力アイテムとも使いません。(絞込み条件や処理結果のデータが発生しないためです。)
マッパークラスに定義された内容を実行するだけの処理となります。
SQLマッパーに定義された SQL が
DELETE FROM WORKTABLEといった SQL になる場合、この SQL には入力パラメータ、出力パラメータのいずれも必要ありません。そこで、入力アイテム、出力アイテムの処理は行っていません。
1: package samples; 2: import java.sql.SQLException; 3: import java.sql.Statement; 4: import jp.ne.mki.wedge.run.db.dc.SqlDataControl; 5: import jp.ne.mki.wedge.run.interfaces.DataInterface; 6: import jp.ne.mki.wedge.run.interfaces.DcRequest; 7: 8: public class SimpleDeleteDc extends SqlDataControl { 9: 10: protected DataInterface[] executeSql(DcRequest req) throws SQLException { 11: int updatedRecordCount = 0; 12: Statement stmt = null; 13: 14: try { 15: stmt = req.createStatement(); 16: updatedRecordCount = stmt.executeUpdate(req.getSql()); 17: req.setUpdateErrorLine(0); 18: } catch (SQLException ex) { 19: req.setUpdateErrorLine(1); 20: throw ex; 21: } finally { 22: req.setUpdateTargetCount(0); 23: req.setDbAccessCount(1); 24: req.setDbUpdatedCount(updatedRecordCount); 25: 26: req.closeDbObject(stmt); 27: } 28: 29: return null; 30: } 31: }
次に入力アイテムを処理するマッパークラスのコーディングについて説明します。
ここでは例として、次のような
UPDATE WORKTABLE SET NAME=? WHERE ID=?といった、指定された条件に該当するレコードに対してだけ、値を更新する SQL を実行します。
1: package samples; 2: import java.io.IOException; 3: import java.sql.PreparedStatement; 4: import java.sql.SQLException; 5: import java.text.ParseException; 6: import jp.ne.mki.wedge.run.db.dc.SqlDataControl; 7: import jp.ne.mki.wedge.run.interfaces.DBDataConvertInterface; 8: import jp.ne.mki.wedge.run.interfaces.DataInterface; 9: import jp.ne.mki.wedge.run.interfaces.DcRequest; 10: 11: public class SimpleUpdateDc extends SqlDataControl { 12: 13: protected DataInterface[] executeSql(DcRequest req) throws SQLException, ParseException, IOException { 14: PreparedStatement stmt = null; 15: int colCount = req.getColumns(); 16: int rowCount = req.getRows(); 17: int updatedCount = 0; 18: int updatedRecordCount = 0; 19: int errorRowNo = 0; 20: 21: try { 22: DataInterface[] inItemArray = req.getInputRecordArray(); 23: DBDataConvertInterface[] dbCvIn = req.getInDbCvClassArray(); 24: stmt = req.prepareStatement(); 25: // stmt = req.prepareStatement(req.getSql()); 26: 27: for (int ii = 0; ii < rowCount; ii++) { 28: errorRowNo++; 29: 30: for (int jj = 0; jj < colCount; jj++) { 31: String data = inItemArray[jj].getString(ii); 32: if (dbCvIn[jj] instanceof DBDataConvert) { 33: ((DBDataConvert) dbCvIn[jj]).setObject(stmt, jj + 1, data); 34: } else { 35: dbCvIn[jj].setData(stmt, jj + 1, data); 36: } 37: } 38: 39: int count = stmt.executeUpdate(); 40: if (count > 0) { 41: updatedCount++; 42: updatedRecordCount += count; 43: } 44: } 45: req.setUpdateErrorLine(0); 46: } catch (SQLException ex) { 47: req.setUpdateErrorLine(errorRowNo); 48: throw ex; 49: } finally { 50: req.setUpdateTargetCount(rowCount); 51: req.setDbAccessCount(updatedCount); 52: req.setDbUpdatedCount(updatedRecordCount); 53: 54: req.closeDbObject(stmt); 55: } 56: 57: return null; 58: } 59: }
req.prepareStatement(req.getSql());を実行するのと同じ動作になります。
次に、全件検索の SQL を例にとり、出力アイテムを使ったマッパークラスのコーディングについて説明します。
ここでは例として次のような SQL を実行します。
SELECT ID, NAME FROM WORKTABLEID, NAME という 2つのカラムが検索対象となっていますので、この 2つのカラムを出力アイテムにセットするためのコーディングが追加されています。
1: package samples; 2: import java.io.IOException; 3: import java.sql.ResultSet; 4: import java.sql.SQLException; 5: import java.sql.Statement; 6: import jp.ne.mki.wedge.run.db.dc.SqlDataControl; 7: import jp.ne.mki.wedge.run.interfaces.DBDataConvertInterface; 8: import jp.ne.mki.wedge.run.interfaces.DataInterface; 9: import jp.ne.mki.wedge.run.interfaces.DcRequest; 10: 11: public class SimpleQueryAllRecordsDC extends SqlDataControl { 12: 13: protected DataInterface[] executeSql(DcRequest req) throws SQLException, IOException { 14: DataInterface[] outItemArray = null; 15: int readRowCount = 0; 16: Statement stmt = null; 17: ResultSet rs = null; 18: 19: try { 20: stmt = req.createStatement(); 21: rs = stmt.executeQuery(req.getSql()); 22: int outColumnCount = rs.getMetaData().getColumnCount(); 23: outItemArray = createOutputDataArray(outColumnCount); 24: DBDataConvertInterface[] dbCvOut = req.getOutDbCvClassArray(); 25: while (rs.next()) { 26: for (int ii = 0; ii < outColumnCount; ii++) { 27: String data; 28: if (dbCvOut[ii] instanceof DBDataConvert) { 29: data = ((DBDataConvert) dbCvOut[ii]).getObject(rs, ii + 1); 30: } else { 31: data = dbCvOut[ii].getData(rs, ii + 1); 32: } 33: outItemArray[ii].addString(data); 34: } 35: readRowCount++; 36: } 37: } finally { 38: req.setDbAccessCount(readRowCount); 39: req.closeDbObject(rs); 40: req.closeDbObject(stmt); 41: } 42: 43: return outItemArray; 44: } 45: }
次に、絞込み条件付き検索の SQL を例にとり、入力アイテム出力アイテムを使ったマッパークラスのコーディングについて説明します。
ここでは例として次のような SQL を実行します。
SELECT NAME FROM WORKTABLE WHERE ID=?ここでは ID カラムに検索条件を設定し、NAME カラムのデータを検索しますので、マッパークラスは、入力アイテムをセットし、出力アイテムを受け取る処理を行います。
1: package samples; 2: import java.io.IOException; 3: import java.sql.PreparedStatement; 4: import java.sql.ResultSet; 5: import java.sql.SQLException; 6: import java.text.ParseException; 7: import jp.ne.mki.wedge.run.db.dc.SqlDataControl; 8: import jp.ne.mki.wedge.run.interfaces.DBDataConvertInterface; 9: import jp.ne.mki.wedge.run.interfaces.DataInterface; 10: import jp.ne.mki.wedge.run.interfaces.DcRequest; 11: 12: public class SimpleQueryDC extends SqlDataControl { 13: 14: protected DataInterface[] executeSql(DcRequest req) throws SQLException, ParseException, IOException { 15: 16: int rowCount = req.getRows(); 17: DataInterface[] outItemArray = null; 18: int readRowCount = 0; 19: 20: DataInterface[] inItemArray = req.getInputRecordArray(); 21: PreparedStatement stmt = null; 22: 23: try { 24: int colCount = req.getColumns(); 25: DBDataConvertInterface[] dbCvIn = req.getInDbCvClassArray(); 26: DBDataConvertInterface[] dbCvOut = req.getOutDbCvClassArray(); 27: stmt = req.prepareStatement(); 28: 29: for (int ii = 0; ii < rowCount; ii++) { 30: for (int jj = 0; jj < colCount; jj++) { 31: String data = inItemArray[jj].getString(ii); 32: if (dbCvIn[jj] instanceof DBDataConvert) { 33: ((DBDataConvert) dbCvIn[jj]).setObject(stmt, jj + 1, data); 34: } else { 35: dbCvIn[jj].setData(stmt, jj + 1, data); 36: } 37: } 38: 39: ResultSet rs = null; 40: 41: try { 42: rs = stmt.executeQuery(); 43: int outColumnCount = rs.getMetaData().getColumnCount(); 44: if (outItemArray == null) { 45: outItemArray = createOutputDataArray(outColumnCount); 46: } 47: 48: while (rs.next()) { 49: for (int jj = 0; jj < outColumnCount; jj++) { 50: String data; 51: if (dbCvOut[jj] instanceof DBDataConvert) { 52: data = ((DBDataConvert) dbCvOut[jj]).getObject(rs, jj + 1); 53: } else { 54: data = dbCvOut[jj].getData(rs, jj + 1); 55: } 56: outItemArray[jj].addString(data); 57: } 58: readRowCount++; 59: } 60: } finally { 61: req.closeDbObject(rs); 62: } 63: } 64: } finally { 65: req.setDbAccessCount(readRowCount); 66: req.closeDbObject(stmt); 67: } 68: 69: return outItemArray; 70: } 71: }
ここでは表タイプを使って、PL/SQL に配列を渡し、結果も配列で受け取るためのサンプルについて説明します。
create or replace type StringList as table of varchar2(16);16桁の可変文字列を要素として保持する表タイプを、「StringList」という名称で定義します。
create or replace package array as procedure ReverseStringList(InputString in StringList, OutputString out StringList); end array;表タイプ「StringList」を入力項目、出力項目として受け渡しするプロシージャを パッケージ「array」に「ReverseStringList」という名称で定義します。
create or replace package body array as procedure ReverseStringList(InputString in StringList, OutputString out StringList) as ListCount number(3); ii number(3); idx number(3); begin ListCount := InputString.count; OutputString := StringList(); OutputString.extend(ListCount); idx := ListCount; FOR ii IN 1..ListCount LOOP OutputString(ii) := InputString(idx); idx := idx - 1; END LOOP; end ReverseStringList; end array;受け取った可変文字列の配列を、逆の順番に並び替えて呼び出し元に返すプロシージャを定義します。
1: package samples; 2: import java.sql.Array; 3: import java.sql.CallableStatement; 4: import java.sql.SQLException; 5: import java.sql.Types; 6: 7: import oracle.sql.ARRAY; 8: import oracle.sql.ArrayDescriptor; 9: import jp.ne.mki.wedge.run.db.dc.SqlDataControl; 10: import jp.ne.mki.wedge.run.interfaces.DataInterface; 11: import jp.ne.mki.wedge.run.interfaces.DcRequest; 12: 13: public class SimpleSpDC extends SqlDataControl { 14: private final static String TABLE_TYPE_NAME = "STRINGLIST"; 15: private final static String SQL = "{call array.ReverseStringList(?,?)}"; 16: 17: protected DataInterface[] executeSql(DcRequest req) throws SQLException { 18: CallableStatement stmt = null; 19: DataInterface[] inItemArray = req.getInputRecordArray(); 20: String[] inStringArray = null; 21: DataInterface[] outItemArray = null; 22: 23: try { 24: int itemSize = inItemArray[0].getSize(); 25: inStringArray = new String[itemSize]; 26: for (int ii = 0; ii < itemSize; ii++) { 27: String data = inItemArray[0].getString(ii); 28: inStringArray[ii] = data; 29: } 30: 31: stmt = req.prepareCall(SQL); 32: ArrayDescriptor desc = ArrayDescriptor.createDescriptor(TABLE_TYPE_NAME, stmt.getConnection()); 33: ARRAY arrayIn = new ARRAY(desc, stmt.getConnection(), inStringArray); 34: stmt.setArray(1, arrayIn); 35: stmt.registerOutParameter(2, Types.ARRAY, TABLE_TYPE_NAME); 36: stmt.execute(); 37: 38: Array arrayOut = stmt.getArray(2); 39: String[] stringArray = (String[]) arrayOut.getArray(); 40: outItemArray = createOutputDataArray(1); 41: int outSize = stringArray.length; 42: DataInterface di = outItemArray[0]; 43: for (int ii = 0; ii < outSize; ii++) { 44: di.addString(stringArray[ii]); 45: } 46: } finally { 47: req.closeDbObject(stmt); 48: } 49: 50: return outItemArray; 51: } 52: }
実装したマッパークラスを使うためには、いくつかの設定が必要となります。
ここでは、SimpleQueryDC を使う場合の手順について説明します。
まずマッパークラスのソースをコンパイルして class ファイルを生成します。
コンパイルを行うには、IDE(統合開発環境)を使う方法と、JDK を使う方法がありますが、IDE の場合は、IDE のツールによって設定が異なりますので、ここでは JDK を使ってコンパイルを行う方法について説明します。
コンパイルを行うには、CLASSPATH に wedge-common-1.4.0.jar, wedge-common-server-1.4.0.jar, wedge-optional-1.4.0.jar, wedge-run-common-1.4.0.jar, wedge-run-data-1.4.0.jar, wedge-run-server-1.4.0.jar を設定します。
set JAVA_HOME=c:\jdk1.7.0_13 set PATH=%JAVA_HOME%\bin;%PATH% set CLASSPATH=c:\Tomcat6.0\webapps\webtribe\WEB-INF\lib\wedge-common-1.4.0.jar;\WEB-INF\lib\wedge-common-server-1.4.0.jar;\WEB-INF\lib\wedge-optional-1.4.0.jar;\WEB-INF\lib\wedge-run-common-1.4.0.jar;\WEB-INF\lib\wedge-run-data-1.4.0.jar;\WEB-INF\lib\wedge-run-server-1.4.0.jar javac SimpleQueryDC.javaコンパイルが通ると、SimpleQueryDC.class というファイルが作成されます。
論理名 | シンプルクエリDC |
物理名 | SimpleQueryDC |
クラス名 | samples.SimpleQueryDC |
create table worktable ( id number(7) not null, name varchar2(16), version varchar2(16) ); alter table worktable add constraint pk_worktable primary key (id); insert into worktable values(1,'Sparkler','1.1.4'); insert into worktable values(2,'Pumpkin','1.1.5'); insert into worktable values(3,'Abigail','1.1.6'); insert into worktable values(4,'Brutus','1.1.7'); insert into worktable values(5,'Chelsea','1.1.8'); insert into worktable values(6,'Playground','1.2'); insert into worktable values(7,'Cricket','1.2.2'); insert into worktable values(8,'Kestrel','1.3'); insert into worktable values(9,'Ladybird','1.3.1'); insert into worktable values(10,'Merlin','1.4.0'); insert into worktable values(11,'Hopper','1.6.0'); insert into worktable values(12,'Mantis','1.4.2'); insert into worktable values(13,'Tiger','1.5.0'); insert into worktable values(14,'DragonFly','1.5.1'); insert into worktable values(15,'Mustang','1.6.0'); commit;
コンパイルしたマッパークラスのクラスファイル(SimpleQueryDC.class)をコピーします。
md c:\Tomcat6.0\webapps\webtribe\WEB-INF\classes md c:\Tomcat6.0\webapps\webtribe\WEB-INF\classes\samples copy SimpleQueryDC.class c:\Tomcat6.0\webapps\webtribe\WEB-INF\classes\samplesLinux の場合
mkdir -p /opt/jakarta-tomcat-6.0/webapps/webtribe/WEB-INF/classes/samples cp SimpleQueryDC.class /opt/jakarta-tomcat-6.0/webapps/webtribe/WEB-INF/classes/samples
classes ディレクトリを CLASSPATH に追加します。
(変更前) set CLASSPATH=%JARFILE_CORE%;%RUNJDBC%
(変更後) set CLASSPATH=classes;%JARFILE_CORE%;%RUNJDBC%
(変更前) CLASSPATH=%JARFILE_CORE%;%RUNJDBC%
(変更後) CLASSPATH=classes;%JARFILE_CORE%;%RUNJDBC%
(変更前) set CLASSPATH=${JARFILE_CORE}:${RUNJDBC}
(変更後) set CLASSPATH=classes:${JARFILE_CORE}:${RUNJDBC}
DBServerを再起動し、CLASSPATH の設定を有効にします。
トランザクションテスト等で作成したSQLマッパーを実行し、動作を確認します。
トレースログで、作成したSQLマッパーが呼び出されているかどうか確認することができます。
●図7. [トランザクションテスト]
[トレースログ]
[2004/05/10 19:49:51]
*DC Class
[samples.SimpleQueryDC]
*SQL
[SELECT NAME FROM WORKTABLE WHERE ID = ? ]
*Input DB convert class
[]
*Input data
[12]
*Output DB convert class
[]
*Output data
[Mantis]