MySQLメモ013:INSERT後にAUTO_INCREMENTなカラムの値を取得する方法
Java+MySQLなWEBアプリにおいて、AUTO_INCREMENTなカラムを持つテーブルにINSERTでレコードを挿入してから、その新規レコードのAUTO_INCREMENTなカラムの値を取得する方法について、ちょっとてこずったのでメモ。
環境は以下。
Java:1.6.0_31
MySQL:5.5.19
本やネットで調べると LAST_INSERT_ID() というMySQLの関数を使う方法もあるようだが、ここはせっかくなのでMySQLのJDBCドライバ(MySQL Connector/J)が提供するAPIを使ってみた。
サンプルコードfinal String sql = "INSERT INTO orders (customer_name, address, payment) VALUES (?, ?, ?)"; DataSource dataSource = (DataSource)context.lookup("java:comp/env/jdbc/mysql"); Connection conn = dataSource.getConnection(); PreparedStatement statement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); statement.setString(1, customerName); statement.setString(2, address); statement.setInt(3, payment); statement.executeUpdate(); // 上記の処理で登録したデータのAUTO_INCREMENTで生成されたIDを取得する PreparedStatement stmt2 = (PreparedStatement)((DelegatingPreparedStatement) statement) .getInnermostDelegate(); ResultSet rs = ((com.mysql.jdbc.PreparedStatement)stmt2).getGeneratedKeys(); if (rs.next()) { id = rs.getInt(1); } else { throw new SQLException("failure: retrieve new id"); }
上記のコードのWEBアプリでは、JNDIで DataSource を取得し DataSource.getConnection() で java.sql.Connection を取得して変数connに入れている。
そのconnで作成した PreparedStaement を作成し statement に代入(5行目)する。ここで使用する prepareStatement() は引数にSQLとフラグを取るもので、フラグには Statement.RETURN_GENERATED_KEYS をセットする。
java.sql インタフェース Connection PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException 自動生成キーを取得する機能を持つデフォルトの PreparedStatement オブジェクトを生成します。 パラメータ: sql - 1 つ以上の '?' IN パラメータプレースホルダーを含めることができる SQL 文 autoGeneratedKeys - 自動生成キーを返すかどうかを示すフラグ。Statement.RETURN_GENERATED_KEYS または Statement.NO_GENERATED_KEYS 戻り値: プリコンパイルされた SQL 文を含む新しい PreparedStatement オブジェクト。自動生成キーを返す機能を持つ 例外: SQLException - データベースアクセスエラーが発生した場合、このメソッドがクローズされた接続に対して呼び出された場合、または指定されたパラメータが自動生成キーを返すかどうかを示す Statement 定数でない場合 SQLFeatureNotSupportedException - JDBC ドライバが定数 Statement.RETURN_GENERATED_KEYS を指定したこのメソッドをサポートしない場合
作成した PreparedStaement は com.mysql.jdbc.PreparedStatement ではないらしい。statement を com.mysql.jdbc.PreparedStatement でキャストしようとすると例外が発生する。
そこで、 statement を org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement にキャストし、getInnermostDelegate() で内部に保持されていた PreparedStatement を取得し stmt2 に代入する(12-15行目)。この取得した PreparedStatement は com.mysql.jdbc.PreparedStatement らしいので getGeneratedKeys() で ResultSet を取得し AUTO_INCREMENT なカラムの値を取得する(15,17行目)。
org.apache.commons.dbcp クラス DelegatingPreparedStatement public PreparedStatement getInnermostDelegate() 内部に保持する PreparedStatement が DelegatingPreparedStatement でない場合にはその PreparedStatement を返し、それ以外の場合には再帰的に getDelegate() をコールします。 従ってこのメソッドは DelegatingPreparedStatement ではない根本の処理の委託先となる PreparedStatement を返し、 DelegatingPreparedStatement の連鎖の中に処理の委託先が見つからない場合には null を返します。 このメソッドはネストした DelegatingPreparedStatement から 本来の PreparedStatement を取得したい場合に有用です。
JNDIを使用せず下記のように Connection を取得した場合は DelegatingPreparedStatement#getInnermostDelegate() は不要で、直接キャストして getGeneratedKeys() を使えばよい。
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/java_sample_db", "java", "password");
参考ページ:MySQL :: MySQL 5.1 リファレンスマニュアル :: 24.4.5.1 JDBC の基本コンセプト
« MySQLメモ012:ユーザー管理 その2 | Main | 100円ショップでスタイラス買った »
「Java」カテゴリの記事
- 正規表現メモ(2013.10.07)
- Androidアプリ開発メモ068:Tweenアニメーション(2012.11.18)
- Androidアプリ開発メモ067:NDKのサンプルを動かしてみた(2012.09.10)
- JNI その2:ネイティブコードからJavaメソッドを呼び出す(2012.08.29)
- JNI その1:Javaからネイティブコードを呼び出す(2012.08.26)
「MySQL」カテゴリの記事
- MySQLメモ020:INSERT後にAUTO_INCREMENTなカラムの値を取得する方法(PDO編)(2015.02.14)
- MySQLメモ019:TIMESTAMP型の列には勝手にNOT NULL制約とDEFAULT制約が付く(2015.02.12)
- MySQLメモ018:MySQL WorkbenchでTRUNCATEできるようにする(2015.02.11)
- MySQLメモ017:CREATE文、AUTO_INCREMENT、ENGINE(2015.02.08)
- SQLインジェクション その7(2013.10.14)
The comments to this entry are closed.
TrackBack
Listed below are links to weblogs that reference MySQLメモ013:INSERT後にAUTO_INCREMENTなカラムの値を取得する方法:
Comments