ブライアンローチによって受け入れられた答えは正しいです。私はいくつかの考えと完全なコードの例を追加しています。
RETURN_GENERATED_KEYS
「生成されたキーを返す」という意味ではありません</
h1 >
元のポスターは、当然のことながら、旗の言い回しによって混乱しているようStatement.RETURN_GENERATED_KEYS
です。直感に反して、このフラグを渡してもメソッドの動作は変わりません。PreparedStatement::executeUpdate
このメソッドは常にint
、実行されたSQLの影響を受ける行数であるを返します。「executeUpdate」メソッドは、生成されたキーを返すことはありません。
int countRowsAffected = pstmt.executeUpdate(); // Always return number of rows affected, *not* the generated keys.
尋ねなさい、そうすればあなたがたは受け取るだろう
生成されたキーが必要な場合は、次の2つの手順を実行する必要があります。
- 旗を渡す、そして
ResultSet
生成されたキー値のみを含む行で構成されていることを要求します。
この配置により、他の望ましい動作を維持しながら、生成されたキーを取り戻す動作を追加して、影響を受ける行数のカウントを取得できます。
サンプルコード
これは、データフィードからデータを取得するJava8アプリから取得したほぼ実際の例です。この文脈では、本格的な例の方が最小限の例よりも役立つと思います。
細かい点…このコードは、構文上またはその他の方法で完全ではない可能性があります。これは、実際のソースコードをコピーして貼り付けて変更したためです。テーブルの代理主キーとして、整数ではなくUUIDデータ型を使用しています。クラスとは私自身のものであり、その詳細はここでは重要ではありません。と変数は、私自身のアプリの意味のあるデータの置き換えです。私のロギング呼び出しはSLF4Jフレームワークに対して行われます。UUIDの16進文字列は、ログ内のレポートを元のソースコードにリンクするための便利な方法です。データベースはPostgresですが、この種のコードは、生成されたキーのレポートをサポートするすべてのデータベースで機能するはずです。CharHelper
DBHelper
x
y
public UUID dbWrite ( String x , String y , DateTime whenRetrievedArg ) {
if ( whenRetrievedArg == null ) {
logger.error( "Passed null for whenRetrievedArg. Message # 2112ed1a-4612-4d5d-8cc5-bf27087a350d." );
return null;
}
Boolean rowInsertComplete = Boolean.FALSE; // Might be used for debugging or logging or some logic in other copy-pasted methods.
String method = "Method 'dbWrite'";
String message = "Insert row for some_table_ in " + method + ". Message # edbea872-d3ed-489c-94e8-106a8e3b58f7.";
this.logger.trace( message );
String tableName = "some_table_";
java.sql.Timestamp tsWhenRetrieved = new java.sql.Timestamp( whenRetrievedArg.getMillis() ); // Convert Joda-Time DatTime object to a java.sql.Timestamp object.
UUID uuidNew = null;
StringBuilder sql = new StringBuilder( AbstractPersister.INITIAL_CAPACITY_OF_SQL_STRING ); // private final static Integer INITIAL_CAPACITY_OF_SQL_STRING = 1024;
sql.append( "INSERT INTO " ).append( tableName ).append( CharHelper.CHAR.PAREN_OPEN_SPACED ).append( " x_ , y_ " ).append( CharHelper.CHAR.PAREN_CLOSED ).append( DBHelper.SQL_NEWLINE );
sql.append( "VALUES ( ? , ? , ? ) " ).append( DBHelper.SQL_NEWLINE );
sql.append( ";" );
try ( Connection conn = DBHelper.instance().dataSource().getConnection() ;
ここでステップ1RETURN_GENERATED_KEYS
を実行し、フラグを渡します。
PreparedStatement pstmt = conn.prepareStatement( sql.toString() , Statement.RETURN_GENERATED_KEYS ); ) {
引き続きステートメントの準備と実行を行います。int countRows = pstmt.executeUpdate();
生成されたキーではなく、影響を受けた行の数を返すことに注意してください。
pstmt.setString( 1 , x );
pstmt.setString( 2 , y );
pstmt.setTimestamp( 3 , tsWhenRetrieved );
// Execute
int countRows = pstmt.executeUpdate(); // Always returns an int, a count of affected rows. Does *not* return the generated keys.
if ( countRows == 0 ) { // Bad.
this.logger.error( "Insert into database for new " + tableName + " failed to affect any rows. Message # 67e8de7e-67a5-42a6-a4fc-06929211e6e3." );
} else if ( countRows == 1 ) { // Good.
rowInsertComplete = Boolean.TRUE;
} else if ( countRows > 1 ) { // Bad.
rowInsertComplete = Boolean.TRUE;
this.logger.error( "Insert into database for new " + tableName + " failed, affecting more than one row. Should not be possible. Message # a366e215-6cf2-4e5c-8443-0b5d537cbd68." );
} else { // Impossible.
this.logger.error( "Should never reach this Case-Else with countRows value " + countRows + " Message # 48af80d4-6f50-4c52-8ea8-98856873f3bb." );
}
ここでは、ステップ2を実行し、生成されたキーのResultSetを要求します。この例の場合、単一の行を挿入し、生成された単一のキーが返されることを期待しています。
if ( rowInsertComplete ) {
// Return new row’s primary key value.
ResultSet genKeys = pstmt.getGeneratedKeys();
if ( genKeys.next() ) {
uuidNew = ( UUID ) genKeys.getObject( 1 ); // ResultSet should have exactly one column, the primary key of INSERT table.
} else {
logger.error( "Failed to get a generated key returned from database INSERT. Message # 6426843e-30b6-4237-b110-ec93faf7537d." );
}
}
残りはエラー処理とクリーンアップです。このコードの下部に、挿入されたレコードの生成された主キーであるUUIDが返されることに注意してください。
} catch ( SQLException ex ) {
// We expect to have occasional violations of unique constraint on this table in this data-scraping app.
String sqlState = ex.getSQLState();
if ( sqlState.equals( DBHelper.SQL_STATE.POSTGRES.UNIQUE_CONSTRAINT_VIOLATION ) ) { // SqlState code '23505' = 'unique_violation'.
this.logger.trace( "Found existing row when inserting a '" + tableName + "' row for y: " + y + ". Expected to happen on most attempts. Message # 0131e8aa-0bf6-4d19-b1b3-2ed9d333df27." );
return null; // Bail out.
} else { // Else any other exception, throw it.
this.logger.error( "SQLException during: " + method + " for table: " + tableName + ", for y: " + y + ". Message # 67908d00-2a5f-4e4e-815c-5e5a480d614b.\n" + ex );
return null; // Bail out.
}
} catch ( Exception ex ) {
this.logger.error( "Exception during: " + method + " for table: " + tableName + ", for y: " + y + ". Message # eecc25d8-de38-458a-bb46-bd6f33117969.\n" + ex );
return null; // Bail out.
}
if ( uuidNew == null ) {
logger.error( "Returning a null uuidNew var. SQL: {} \nMessage # 92e2374b-8095-4557-a4ed-291652c210ae." , sql );
}
return uuidNew;
}