📌
Javaのtry-with-resourcesを利用してrollbackする
どこかでtry-with-resourcesを利用した際にrollbackしようとするとコネクションがクローズされていて出来ないみたいなものを見たので、これで出来るよという記事です。
rollback出来ないコード
問題のコードです。
final String connectionUrl = "jdbc:postgresql://localhost:5432/postgres";
final String user = "postgres";
final String password = "password";
final String sql1 = "insert into books values (2, 'Effective Java');";
final String sql2 = "insert into books values (3, 'Java言語で学ぶデザインパターン入門');";
Connection connection = DriverManager.getConnection(connectionUrl, user, password);
boolean isThrowException = true;
try (connection;
PreparedStatement statement1 = connection.prepareStatement(sql1);
PreparedStatement statement2 = connection.prepareStatement(sql2);
) {
connection.setAutoCommit(false);
statement1.executeUpdate();
if (isThrowException) {
throw new SQLException();
}
statement2.executeUpdate();
connection.commit();
} catch (Exception e) {
// ここに到達したときにはconnectionはcloseされている
if (connection != null && !connection.isClosed()) {
connection.rollback();
}
e.printStackTrace();
}
connection, statement1, statement2を自動クローズ対象のリソースとして指定しています。
この書き方の場合、コメントにも書いてあるようにcatchの中に入ったときにはすでにクローズされているためロールバック出来ません。
これはJavaの仕様でcatch, finallyに入った際にはすでにクローズされているためです。
JLS -> Extended try-with-resources
try-with-resourcesを利用してロールバックするコード
connectionで最初に囲ってネストした中にstatementを囲ってあげれば実現出来ます。
final String connectionUrl = "jdbc:postgresql://localhost:5432/postgres";
final String user = "postgres";
final String password = "password";
final String sql1 = "insert into books values (2, 'Effective');";
final String sql2 = "insert into books values (3, 'デザインパターン');";
boolean isThrowException = true;
try (Connection connection = DriverManager.getConnection(connectionUrl, user, password)) {
connection.setAutoCommit(false);
try (PreparedStatement statement1 = connection.prepareStatement(sql1);
PreparedStatement statement2 = connection.prepareStatement(sql2)
) {
statement1.executeUpdate();
if (isThrowException) {
throw new SQLException();
}
statement2.executeUpdate();
connection.commit();
} catch (SQLException e) {
connection.rollback();
throw e;
}
} catch (Exception e) {
e.printStackTrace();
}
Discussion