[+/-]
このセクションでは、JDBC の一般的な背景を説明します。
アプリケーション サーバの外で JDBC
を使用している場合、DriverManager
クラスは Connections の確立を管理します。
DriverManager
は、Connections をどの
JDBC ドライバ
で作成するべきかの指示を必要とします。この最も簡単な方法は、java.sql.Driver
インターフェイスを実装するクラスで
Class.forName()
を使用することです。MySQL Connector/J
では、このクラスの名称は
com.mysql.jdbc.Driver
になります。このメソッドで、外部構成ファイルを使用して、データベースへの接続に使用するドライバ
クラス名とドライバ
パラメータを供給することが可能です。
次のセクションの Java
コードは、アプリケーションの
main()
メソッドから MySQL Connector/J
を登録する方法を表しています。
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; // Notice, do not import com.mysql.jdbc.* // or you will have problems! public class LoadDriver { public static void main(String[] args) { try { // The newInstance() call is a work around for some // broken Java implementations Class.forName("com.mysql.jdbc.Driver").newInstance(); } catch (Exception ex) { // handle the error } }
ドライバが DriverManager
に登録されたら、DriverManager.getConnection()
を呼び出すことによって、特定のデータベースに接続される
Connection
インスタンスを取得することができます :
例 24.1. DriverManager
から接続を取得する
この例は、DriverManager
から
Connection
インスタンスを取得する方法を示しています。getConnection()
メソッドにはいくつかの異なる署名があります。JDK
に添付されている API
資料で、詳しい使用方法を確認してください。
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; ... try { Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=monty&password=greatsqldb"); // Do something with the Connection ... } catch (SQLException ex) { // handle any errors System.out.println("SQLException: " + ex.getMessage()); System.out.println("SQLState: " + ex.getSQLState()); System.out.println("VendorError: " + ex.getErrorCode()); }
Connection
が確立されたら、Statement
と
PreparedStatement
のオブジェクトの作成、そしてデータベースに関するメタデータの摘出に使用できます。これについては次のセクションで説明されます。
Statement
オブジェクトは、後で説明されるように、基本的な
SQL クエリを実行し、ResultSet
クラスを通しての結果の摘出を可能にします。
Statement
を作成するには、前で説明した
DriverManager.getConnection()
か
Data- Source.getConnection()
メソッドのひとつを介して摘出した
Connection
オブジェクトで
createStatement()
メソッドを呼び出します。
Statement
インスタンスを得たら、使いたい SQL で
executeQuery( String)
メソッドを呼び出し、SELECT
クエリを実行することができます。
データベースのデータを更新するには、executeUpdate(String
SQL)
メソッドを使用します。このメソッドは、update
文に影響を受けた行の数を戻します。
SQL 文が SELECT
、または
UPDATE
/INSERT
になるかが事前に分からない場合は、execute(String
SQL)
メソッドを使用することができます。このメソッドは、SQL
クエリが SELECT
の場合は true
、UPDATE
、INSERT
、もしくは DELETE
文の場合は
false を返します。ステートメントが
SELECT
クエリの場合は、getResultSet()
メソッドを呼び出すことで結果を摘出できます。ステートメントが
UPDATE
、INSERT
、もしくは DELETE
文であれば、Statement
インスタンスで getUpdateCount()
を呼び出すことによって、影響を受けた行の数を呼び出すことができます。
例 24.2. java.sql.Statement を使用して SELECT
クエリを実行する
// assume that conn is an already created JDBC connection Statement stmt = null; ResultSet rs = null; try { stmt = conn.createStatement(); rs = stmt.executeQuery("SELECT foo FROM bar"); // or alternatively, if you don't know ahead of time that // the query will be a SELECT... if (stmt.execute("SELECT foo FROM bar")) { rs = stmt.getResultSet(); } // Now do something with the ResultSet .... } finally { // it is a good idea to release // resources in a finally{} block // in reverse-order of their creation // if they are no-longer needed if (rs != null) { try { rs.close(); } catch (SQLException sqlEx) { // ignore } rs = null; } if (stmt != null) { try { stmt.close(); } catch (SQLException sqlEx) { // ignore } stmt = null; } }
MySQL サーバ バージョン 5.0 からは、Connector/J
3.1.1
以降と使用する場合、java.sql.CallableStatement
インターフェイスは
getParameterMetaData()
メソッドを除いて完全に実装されています。
MySQL ストアド プロシージャの詳細は、 http://dev.mysql.com/doc/mysql/en/stored-procedures.html をご覧ください。
Connector/J は、JDBC の
CallableStatement
インターフェイスを通して、ストアド
プロシージャ機能を露出します。
注意 :
MySQL サーバの現行バージョンは、JDBC
ドライバが呼び出し可能なステートメントに結果セット
メタデータを提供するための十分な情報を返しません。つまり、CallableStatement
を使用すると、ResultSetMetaData
は NULL
を返す場合があります。
次の例は、1 増やされた inOutParam
の値を戻すストアド
プロシージャと、ResultSet
として inputParam
を介して渡されたストリングを示しています :
例 24.3. ストアド プロシージャ
CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), \ INOUT inOutParam INT) BEGIN DECLARE z INT; SET z = inOutParam + 1; SET inOutParam = z; SELECT inputParam; SELECT CONCAT('zyxw', inputParam); END
demoSp
プロシージャを Connector/J
で使用するには、次の手順に従ってください :
Connection.prepareCall()
を使用して、呼び出し可能なステートメントを準備
JDBC エスケープ シンタックスを使用する必要があり、またパラメータ プレースホルダを囲む丸括弧 (()) はオプションではないので注意。
例 24.4. Connection.prepareCall()
の使用
import java.sql.CallableStatement; ... // // Prepare a call to the stored procedure 'demoSp' // with two parameters // // Notice the use of JDBC-escape syntax ({call ...}) // CallableStatement cStmt = conn.prepareCall("{call demoSp(?, ?)}"); cStmt.setString(1, "abcdefg");
注意.
出力パラメータのサポートのためにドライバが行うメタデータの取り出しにより、Connection.prepareCall()
は拡張可能なメソッドです。性能上の理由から、コード内で
CallableStatement
インスタンスを使用して、Connection.prepareCall()
への不要な呼び出しを最小限に抑えてください。
出力パラメータ ( ある場合は ) を登録
出力パラメータ( ストアド
プロシージャの作成時に OUT
または INOUT
と特定されたパラメータ )
の値を取り出すには、JDBC
は、CallableStatement
インターフェイスの様々な
registerOutputParameter()
メソッドを使用して、ステートメントの実行の前にそれらを特定することを要求します
:
例 24.5. 出力パラメータの登録
import java.sql.Types; ... // // Connector/J supports both named and indexed // output parameters. You can register output // parameters using either method, as well // as retrieve output parameters using either // method, regardless of what method was // used to register them. // // The following examples show how to use // the various methods of registering // output parameters (you should of course // use only one registration per parameter). // // // Registers the second parameter as output, and // uses the type 'INTEGER' for values returned from // getObject() // cStmt.registerOutParameter(2, Types.INTEGER); // // Registers the named parameter 'inOutParam', and // uses the type 'INTEGER' for values returned from // getObject() // cStmt.registerOutParameter("inOutParam", Types.INTEGER); ...
入力パラメータ ( ある場合は ) を設定
入力および in/out
パラメータは、PreparedStatement
オブジェクトを対象として設定されます。しかし、CallableStatement
はまた、名前によってパラメータの設定をサポートします
:
例 24.6. CallableStatement
入力パラメータの設定
... // // Set a parameter by index // cStmt.setString(1, "abcdefg"); // // Alternatively, set a parameter using // the parameter name // cStmt.setString("inputParameter", "abcdefg"); // // Set the 'in/out' parameter using an index // cStmt.setInt(2, 1); // // Alternatively, set the 'in/out' parameter // by name // cStmt.setInt("inOutParam", 1); ...
CallableStatement
を実行し、すべての結果セット、もしくは出力パラメータを呼び出す
CallableStatement
はいかなる
Statement
execute メソッド (
executeUpdate()
、executeQuery()
、または
execute()
)
の呼び出しもサポートしますが、最も呼び出しやすいメソッドは
execute()
で、ストアド
プロシージャが結果セットを返すかが事前に分からなくても問題ありません
:
例 24.7. 結果と出力パラメータの値を呼び出す
... boolean hadResults = cStmt.execute(); // // Process all returned result sets // while (hadResults) { ResultSet rs = cStmt.getResultSet(); // process result set ... hadResults = rs.getMoreResults(); } // // Retrieve output parameters // // Connector/J supports both index-based and // name-based retrieval // int outputValue = cStmt.getInt(2); // index-based outputValue = cStmt.getInt("inOutParam"); // name-based ...
JDBC API のバージョン 3.0
より前では、自動インクリメント、または識別カラムをサポートするデータベースからキー値を呼び出す標準の方法がありませんでした。MySQL
に古い JDBC
ドライバを使用すると、Statement
インターフェイスでいつでも MySQL
特有のメソッドを使用でき、また、AUTO_INCREMENT
キーを持つテーブルに INSERT
を発行した後で、クエリ SELECT
LAST_INSERT_ID()
を発行することができました。MySQL
特有メソッド呼び出しの使用はポータブルではなく、AUTO_INCREMENT
キーの値を得るために SELECT
を発行するには、データベースまでもう一度往復する必要があり、最も効率的とはいえません。次のコード部品は、AUTO_INCREMENT
値を呼び出す 3
つの方法を実証します。まず、AUTO_INCREMENT
キーを呼び出し、JDBC-3.0
にアクセスする必要がある場合に推奨されるメソッドである、新しい
JDBC-3.0 メソッド getGeneratedKeys()
使用を実証します。その次の例では、標準の
SELECT LAST_INSERT_ID()
クエリを使用して、同じ値を呼び出す方法を挙げます。最後の例では、insertRow()
メソッドを使用する場合に、更新可能な結果セットが
AUTO_INCREMENT
値を呼び出す方法を示します。
例 24.8. Statement.getGeneratedKeys()
を使った
AUTO_INCREMENT
カラム値の呼び出し
Statement stmt = null; ResultSet rs = null; try { // // Create a Statement instance that we can use for // 'normal' result sets assuming you have a // Connection 'conn' to a MySQL database already // available stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_UPDATABLE); // // Issue the DDL queries for the table for this example // stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial"); stmt.executeUpdate( "CREATE TABLE autoIncTutorial (" + "priKey INT NOT NULL AUTO_INCREMENT, " + "dataField VARCHAR(64), PRIMARY KEY (priKey))"); // // Insert one row that will generate an AUTO INCREMENT // key in the 'priKey' field // stmt.executeUpdate( "INSERT INTO autoIncTutorial (dataField) " + "values ('Can I Get the Auto Increment Field?')", Statement.RETURN_GENERATED_KEYS); // // Example of using Statement.getGeneratedKeys() // to retrieve the value of an auto-increment // value // int autoIncKeyFromApi = -1; rs = stmt.getGeneratedKeys(); if (rs.next()) { autoIncKeyFromApi = rs.getInt(1); } else { // throw an exception from here } rs.close(); rs = null; System.out.println("Key returned from getGeneratedKeys():" + autoIncKeyFromApi); } finally { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // ignore } } }
例 24.9. SELECT LAST_INSERT_ID()
を使った
AUTO_INCREMENT
カラム値の呼び出し
Statement stmt = null; ResultSet rs = null; try { // // Create a Statement instance that we can use for // 'normal' result sets. stmt = conn.createStatement(); // // Issue the DDL queries for the table for this example // stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial"); stmt.executeUpdate( "CREATE TABLE autoIncTutorial (" + "priKey INT NOT NULL AUTO_INCREMENT, " + "dataField VARCHAR(64), PRIMARY KEY (priKey))"); // // Insert one row that will generate an AUTO INCREMENT // key in the 'priKey' field // stmt.executeUpdate( "INSERT INTO autoIncTutorial (dataField) " + "values ('Can I Get the Auto Increment Field?')"); // // Use the MySQL LAST_INSERT_ID() // function to do the same thing as getGeneratedKeys() // int autoIncKeyFromFunc = -1; rs = stmt.executeQuery("SELECT LAST_INSERT_ID()"); if (rs.next()) { autoIncKeyFromFunc = rs.getInt(1); } else { // throw an exception from here } rs.close(); System.out.println("Key returned from " + "'SELECT LAST_INSERT_ID()': " + autoIncKeyFromFunc); } finally { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // ignore } } }
例 24.10. Updatable ResultSets
内の
AUTO_INCREMENT
カラム値の呼び出し
Statement stmt = null; ResultSet rs = null; try { // // Create a Statement instance that we can use for // 'normal' result sets as well as an 'updatable' // one, assuming you have a Connection 'conn' to // a MySQL database already available // stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_UPDATABLE); // // Issue the DDL queries for the table for this example // stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial"); stmt.executeUpdate( "CREATE TABLE autoIncTutorial (" + "priKey INT NOT NULL AUTO_INCREMENT, " + "dataField VARCHAR(64), PRIMARY KEY (priKey))"); // // Example of retrieving an AUTO INCREMENT key // from an updatable result set // rs = stmt.executeQuery("SELECT priKey, dataField " + "FROM autoIncTutorial"); rs.moveToInsertRow(); rs.updateString("dataField", "AUTO INCREMENT here?"); rs.insertRow(); // // the driver adds rows at the end // rs.last(); // // We should now be on the row we just inserted // int autoIncKeyFromRS = rs.getInt("priKey"); rs.close(); rs = null; System.out.println("Key returned for inserted row: " + autoIncKeyFromRS); } finally { if (rs != null) { try { rs.close(); } catch (SQLException ex) { // ignore } } if (stmt != null) { try { stmt.close(); } catch (SQLException ex) { // ignore } } }
上記の例のコードを使用する時は、次の出力を取得してください
: getGeneratedKeys()
から戻されたキー : 1 SELECT
LAST_INSERT_ID()
から戻されたキー : 1
挿入された行に戻されたキー : 2
関数の値は接続へスコープされているため、SELECT
LAST_INSERT_ID()
クエリの使用がしにくい場合がありますので注意してください。したがって、他のクエリが同じ接続上で発生する場合、値は上書きされます。一方、getGeneratedKeys()
メソッドは Statement
インスタンスにスコープされているので、他のクエリが同じ接続上で発生しても使用が可能ですが、同じ
Statement
インスタンス上では使用できません。