[+/-]
このセクションでは、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
          インスタンス上では使用できません。
        

