JDBC の基本
JDBC では経験豊富な Java データベース開発者向けに概要を説明する必要はありませんが、使用頻度の低い小型のユーティリティ・アプリケーションでのみ Java を使用する場合であっても、この説明は非常に役立つ可能性があります。このセクションでは、データベースにクエリを実行して結果を操作するために頻繁に使用する JDBC のクラスとメソッドの例を提供します。
-
"簡単な JDBC アプリケーション" は、JDBC の基本機能を示す完全だが非常に簡単なアプリケーションです。
-
以下のセクションでは、PreparedStatement と CallableStatement を使用してデータベースにクエリを実行して ResultSet を返す方法を示します。
-
"作成済み文の実行" — 暗黙結合構文を使用する例です。
-
"CallableStatement を使用したストアド・プロシージャの実行" — ストアド・プロシージャを実行する例です。
-
"複数の結果セットを返す" — InterSystems IRIS ストアド・プロシージャによって返される複数の結果セットへのアクセス方法です。
-
-
以下のセクションでは、JDBC 結果セットを使用して、データベースにデータを挿入して更新する方法を紹介します。
-
"データの挿入および生成されるキーの取得" — PreparedStatement および SQL INSERT コマンドを使用します。
-
"結果セットのスクロール" — 結果セットの任意の行にランダムにアクセスします。
-
"トランザクションの使用法" — JDBC トランザクション・モデルを使用して変更をコミットまたはロールバックします。
-
ほとんどの場合、このセクションの例は、アプリケーション全体ではなくコード断片として表されています。これらの例は、基本機能をできる限り簡単かつ明確に示しており、すぐれたコーディング方法の例示を目的としているわけではありません。この例では、dbconnection という接続オブジェクトが既に開かれていて、コード断片すべてが適切な try/catch 文の内側にあることを前提とします。
簡単な JDBC アプリケーション
このセクションでは、最も一般的な JDBC クラスの一部の使用法を例示する非常に簡単な JDBC アプリケーションについて説明します。
-
IRISDataSource オブジェクトは、JDBC アプリケーションを InterSystems IRIS データベースにリンクする Connection オブジェクトの作成に使用されます。
-
Connection オブジェクトは、ダイナミック SQL クエリを実行可能な PreparedStatement オブジェクトの作成に使用されます。
-
PreparedStatement クエリは、要求された行を含む ResultSet オブジェクトを返します。
-
ResultSet オブジェクトには、特定の行に移動し、その行の特定の列の読み取りまたは更新を行うために使用することができるメソッドがあります。
これらのクラスについては、すべて以降のセクションで詳しく説明します。
最初に、JDBC パッケージをインポートし、try ブロックを開きます。
import java.sql.*;
import javax.sql.*;
import com.intersystems.jdbc.*;
public class SimpleJDBC{
public static void main() {
try {
// Use IRISDataSource to open a connection
Class.forName ("com.intersystems.jdbc.IRISDriver").newInstance();
IRISDataSource ds = new IRISDataSource();
ds.setURL("jdbc:IRIS://127.0.0.1:1972/User");
Connection dbconn = ds.getConnection("_SYSTEM","SYS");
// Execute a query and get a scrollable, updatable result set.
String sql="Select Name from Demo.Person Order By Name";
int scroll=ResultSet.TYPE_SCROLL_SENSITIVE;
int update=ResultSet.CONCUR_UPDATABLE;
PreparedStatement pstmt = dbconn.prepareStatement(sql,scroll,update);
java.sql.ResultSet rs = pstmt.executeQuery();
// Move to the first row of the result set and change the name.
rs.first();
System.out.println("\n Old name = " + rs.getString("Name"));
rs.updateString("Name", "Bill. Buffalo");
rs.updateRow();
System.out.println("\n New name = " + rs.getString("Name") + "\n");
// Close objects and catch any exceptions.
pstmt.close();
rs.close();
dbconn.close();
} catch (Exception ex) {
System.out.println("SimpleJDBC caught exception: "
+ ex.getClass().getName() + ": " + ex.getMessage());
}
} // end main()
} // end class SimpleJDBC
作成済み文を使用するクエリ
以下のクエリは、作成済み文を使用して、"M" ~ "Z" で始まる名前の会社を担当する “A” ~ "E" で始まる名前の従業員すべてのリストを返します。
Select ID, Name, Company->Name from Demo.Employee
Where Name < ? and Company->Name > ?
Order By Company->Name
作成済み文を実装するには、以下の手順に従います。
-
クエリを含む文字列を作成し、これを使用して PreparedStatement オブジェクトを初期化した後、クエリ・パラメータ値を設定し、クエリを実行します。
String sql= "Select ID, Name, Company->Name from Demo.Employee " + "Where Name < ? and Company->Name > ? " + "Order By Company->Name"; PreparedStatement pstmt = dbconnection.prepareStatement(sql); pstmt.setString(1,"F"); pstmt.setString(2,"L"); java.sql.ResultSet rs = pstmt.executeQuery();
-
結果セットを取得して表示します。
java.sql.ResultSet rs = pstmt.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int colnum = rsmd.getColumnCount(); while (rs.next()) { for (int i=1; i<=colnum; i++) { System.out.print(rs.getString(i) + " "); } System.out.println(); }
CallableStatement によるストアド・プロシージャを使用するクエリ
以下のコードは、ByName (Demo.Person に格納されている InterSystems IRIS ストアド・プロシージャ) を実行します。
-
java.sql.CallableStatement オブジェクトを作成し、これをストアド・プロシージャの名前で初期化します。プロシージャの SqlName は、SP_Demo_By_Name です。これは、Java クライアント・コード内でこの名前がどのように参照されるかを示します。
String sql="call Demo.SP_Demo_By_Name(?)" CallableStatement cs = dbconnection.prepareCall(sql);
-
クエリ・パラメータ値を設定し、このクエリを実行した後、結果セットを繰り返し処理してデータを表示します。
cs.setString(1,"A"); java.sql.ResultSet rs = cs.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int colnum = rsmd.getColumnCount(); while (rs.next()) { for (int i=1; i<=colnum; i++) System.out.print(rs.getString(i) + " "); } System.out.println();
複数の結果セットを返すクエリ
InterSystems IRIS では、複数の結果セットを返すストアド・プロシージャを定義できます。InterSystems JDBC ドライバは、このようなストアド・プロシージャの実行をサポートしています。次に、2 つの結果セットを返す InterSystems IRIS ストアド・プロシージャの例を示します (2 つのクエリ結果の列構造は異なっています)。
/// This class method produces two result sets.
ClassMethod DRS(st) [ ReturnResultsets, SqlProc ]
{
$$$ResultSet("select Name from Demo.Person where Name %STARTSWITH :st")
$$$ResultSet("select Name, DOB from Demo.Person where Name %STARTSWITH :st")
Quit
}
$$$ResultSet は、SQL 文 (文字リテラルとして指定) を作成して実行し結果セットを返す事前定義 InterSystems マクロです。
以下のコードは、このストアド・プロシージャを実行し、返された結果セット両方の繰り返し処理を行います。
-
java.sql.CallableStatement オブジェクトを作成し、これをストアド・プロシージャの名前を使用して初期化します。クエリ・パラメータを設定し、execute を使用して、クエリを実行します。
CallableStatement cs = dbconnection.prepareCall("call Demo.Person_DRS(?)"); cs.setString(1,"A"); boolean success=cs.execute();
-
データを表示する結果セットのペアに繰り返し処理を行います。getResultSet が現在の結果セットを取得したら、getMoreResults は、その結果セットを閉じて、CallableStatement オブジェクトの次の結果セットへ移動します。
if(success) do{ java.sql.ResultSet rs = cs.getResultSet(); ResultSetMetaData rsmd = rs.getMetaData(); for (int j=1; j<rsmd.getColumnCount() + 1; j++) System.out.print(rsmd.getColumnName(j)+ "\t\t"); System.out.println(); int colnum = rsmd.getColumnCount(); while (rs.next()) { for (int i=1; i<=colnum; i++) System.out.print(rs.getString(i) + " \t "); System.out.println(); } System.out.println(); } while (cs.getMoreResults());
データの挿入および生成されるキーの取得
以下のコードは、新しい行を Demo.Person に挿入し、生成される ID キーを取得します。
-
PreparedStatement オブジェクトを作成し、これを SQL 文字列を使用して初期化し、生成されるキーが返されるように指定します。
String sqlIn="INSERT INTO Demo.Person (Name,SSN,DOB) " + "VALUES(?,?,?)"; int keys=Statement.RETURN_GENERATED_KEYS; PreparedStatement pstmt = dbconnection.prepareStatement(sqlIn, keys);
-
クエリ・パラメータの値を設定し、更新を実行します。
String SSN = Demo.util.generateSSN(); // generate a random SSN java.sql.Date DOB = java.sql.Date.valueOf("1984-02-01"); pstmt.setString(1,"Smith,John"); // Name pstmt.setString(2,SSN); // Social Security Number pstmt.setDate(3,DOB); // Date of Birth pstmt.executeUpdate();
-
新しい行を挿入するたびに、システムは、その行のオブジェクト ID を自動的に生成します。生成される ID キーは、結果セットに取得され、SSN と共に表示されます。
java.sql.ResultSet rsKeys = pstmt.getGeneratedKeys(); rsKeys.next(); String newID=rsKeys.getString(1); System.out.println("new ID for SSN " + SSN + " is " + newID);
このコードは ID が rsKeys で生成される最初で唯一のキーであることを想定していますが、実際にはこの想定が常に安全であるとは限りません。
-
ID で新しい行を取得し、これを表示します (Age は DOB に基づいて計算される値です)。
String sqlOut="SELECT IName,Age,SSN FROM Demo.Person WHERE ID="+newID; pstmt = dbconnection.prepareStatement(sqlOut); java.sql.ResultSet rsPerson = pstmt.executeQuery(); int colnum = rsPerson.getMetaData().getColumnCount(); rsPerson.next(); for (int i=1; i<=colnum; i++) System.out.print(rsPerson.getString(i) + " "); System.out.println();
結果セットのスクロール
InterSystems JDBC ドライバは、スクロール可能な結果セットをサポートします。これにより、Java アプリケーションでこの結果セット・データを順方向および逆方向に移動できます。prepareStatement() メソッドは、以下のパラメータを使用して、結果セットがどのように機能するかを決定します。
-
resultSetType パラメータは、変更の表示方法を決定します。
-
ResultSet.TYPE_SCROLL_SENSITIVE は、別のプロセスで基本データに対して行われた変更を表示するスクロール可能な結果セットを作成します。
-
ResultSet.TYPE_SCROLL_INSENSITIVE は、現在のプロセスで行われた変更のみを表示するスクロール可能な結果セットを作成します。
-
-
resultSetConcurrency パラメータは、結果セットを更新する場合、ResultSet.CONCUR_UPDATABLE に設定する必要があります。
以下のコードは、スクロール可能な結果セットを作成して使用します。
-
PreparedStatement オブジェクトを作成し、クエリ・パラメータを設定して、このクエリを実行します。
String sql="Select Name, SSN from Demo.Person "+ " Where Name > ? Order By Name"; int scroll=ResultSet.TYPE_SCROLL_SENSITIVE; int update=ResultSet.CONCUR_UPDATABLE; PreparedStatement pstmt = dbconnection.prepareStatement(sql,scroll,update); pstmt.setString(1,"S"); java.sql.ResultSet rs = pstmt.executeQuery();
新しい行が挿入される結果セットには、InterSystems IRIS ID 列を含めないでください。ID 値は、InterSystems IRIS によって自動的に定義されます。
-
このアプリケーションでは、この結果セットを順方向および逆方向にスクロールできます。結果セットのカーソルを最後の行の後ろに移動するには、afterLast を使用します。逆方向にスクロールするには、previous を使用します。
rs.afterLast(); int colnum = rs.getMetaData().getColumnCount(); while (rs.previous()) { for (int i=1; i<=colnum; i++) System.out.print(rs.getString(i) + " "); System.out.println(); }
-
absolute を使用して、特定の行に移動します。このコードでは 3 番目の行の内容が表示されます。
rs.absolute(3); for (int i=1; i<=colnum; i++) System.out.print(rs.getString(i) + " "); System.out.println();
-
relative を使用して、現在の行を基準にした特定の行に移動します。以下のコードでは、最初の行に移動して 2 行下方にスクロールした後、3 行目を再度表示します。
rs.first(); rs.relative(2); for (int i=1; i<=colnum; i++) System.out.print(rs.getString(i) + " "); System.out.println();
-
行を更新するには、カーソルを更新する行に移動し、目的の列を更新してから updateRow を呼び出します。
rs.last(); rs.updateString("Name", "Avery. Tara R"); rs.updateRow();
-
行を挿入するには、カーソルを “挿入行” に移動してからその行の列を更新します。NULL 値が許容されない列がすべて更新されていることを確認します。最後に、insertRow を呼び出します。
rs.moveToInsertRow(); rs.updateString(1, "Abelson,Alan"); rs.updateString(2, Demo.util.generateSSN())); rs.insertRow();
トランザクションの使用法
InterSystems JDBC ドライバは、標準の JDBC トランザクション・モデルをサポートしています。
-
SQL 文をトランザクションにグループ化するには、最初に次のように setAutoCommit() を使用して、自動コミット・モードを無効化する必要があります。
dbconnection.setAutoCommit(false);
-
commit() の最後の実行またはロールバック以降に実行されたすべての SQL 文をデータベースに対してコミットするには、commit() を使用します。
pstmt1.execute(); pstmt2.execute(); pstmt3.execute(); dbconnection.commit();
-
トランザクション内のすべてのトランザクションをロールバックするには、rollback() を使用します。ここで、SQLException がトランザクションで任意の SQL 文によってスローされる場合、rollback() が呼び出されます。
catch(SQLException ex) { if (dbconnection != null) { try { dbconnection.rollback(); } catch (SQLException excep){ // (handle exception) } } }
次に、この例で使用する java.sql.Connection メソッドの概要を説明します。
-
setAutoCommit()
既定では、Connection オブジェクトは自動コミット・モードになっています。このモードでは、SQL 文は実行されるとすぐにコミットされます。複数の SQL 文を 1 つのトランザクションにグループ化するには、最初に setAutoCommit(false) を使用して Connection オブジェクトの自動コミット・モードを終了します。setAutoCommit(true) を使用して、Connection オブジェクトを自動コミット・モードに再設定します。
-
commit()
commit() を実行すると、commit() または rollback() の最後の実行以降に実行されたすべての SQL 文がコミットされます。最初に自動コミットを false に設定しないで commit() を呼び出すと、例外が返されないことに注意してください。
-
rollback()
rollback を実行すると、トランザクションが中止され、トランザクションによって変更されたすべての値が元の状態にリストアされます。
Native SDK for Java は、ここで説明した java.sql トランザクション・モデルに代わるトランザクション・モデルを提供します。Native SDK トランザクション・モデルは ObjectScript トランザクション・メソッドに基づいており、JDBC モデルと互換性はありません。トランザクションに Native SDK メソッド呼び出しが含まれる場合は、Native SDK モデルを使用する必要があります。詳細は、"Native SDK for Java の使用法" を参照してください。