JDBCトランザクションの例
JDBCトランザクションは、一連のSQLステートメントがユニットとして実行されること、すべてのステートメントが正常に実行されること、またはステートメントのどれも実行されないこと(すべての変更をロールバックすること)を確認します。
1. JDBCトランザクションなし
1.1 A JDBC example to insert two rows and update one row.
TransactionExample.java
package com.example.jdbc; import java.math.BigDecimal; import java.sql.*; import java.time.LocalDateTime; public class TransactionExample { public static void main(String[] args) { try (Connection conn = DriverManager.getConnection( "jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password"); Statement statement = conn.createStatement(); PreparedStatement psInsert = conn.prepareStatement(SQL_INSERT); PreparedStatement psUpdate = conn.prepareStatement(SQL_UPDATE)) { statement.execute(SQL_TABLE_DROP); statement.execute(SQL_TABLE_CREATE); // Run list of insert commands psInsert.setString(1, "example"); psInsert.setBigDecimal(2, new BigDecimal(10)); psInsert.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now())); psInsert.execute(); psInsert.setString(1, "kungfu"); psInsert.setBigDecimal(2, new BigDecimal(20)); psInsert.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now())); psInsert.execute(); // Run list of update commands // below line caused error, test transaction // org.postgresql.util.PSQLException: No value specified for parameter 1. psUpdate.setBigDecimal(2, new BigDecimal(999.99)); //psUpdate.setBigDecimal(1, new BigDecimal(999.99)); psUpdate.setString(2, "example"); psUpdate.execute(); } catch (Exception e) { e.printStackTrace(); } } private static final String SQL_INSERT = "INSERT INTO EMPLOYEE (NAME, SALARY, CREATED_DATE) VALUES (?,?,?)"; private static final String SQL_UPDATE = "UPDATE EMPLOYEE SET SALARY=? WHERE NAME=?"; private static final String SQL_TABLE_CREATE = "CREATE TABLE EMPLOYEE" + "(" + " ID serial," + " NAME varchar(100) NOT NULL," + " SALARY numeric(15, 2) NOT NULL," + " CREATED_DATE timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP," + " PRIMARY KEY (ID)" + ")"; private static final String SQL_TABLE_DROP = "DROP TABLE EMPLOYEE"; }
出力、更新は失敗し、例外をスローして、最後に2行が挿入されますが、更新はスキップされます。
org.postgresql.util.PSQLException: No value specified for parameter 1. at org.postgresql.core.v3.SimpleParameterList.checkAllParametersSet(SimpleParameterList.java:257) at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:292) at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441) at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365) at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143) at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:132) at com.example.jdbc.TransactionExample.main(TransactionExample.java:41)
2. JDBCトランザクションの使用
2.1 To enable transaction, set auto commit to false.
conn.setAutoCommit(false); // default true // start transaction block // insert // update // if any errors within the start and end block, // rolled back all changes, none of the statements are executed. // end transaction block conn.commit();
2.2 Same example with JDBC transaction.
TransactionExample.java
package com.example.jdbc; import java.math.BigDecimal; import java.sql.*; import java.time.LocalDateTime; public class TransactionExample { public static void main(String[] args) { try (Connection conn = DriverManager.getConnection( "jdbc:postgresql://127.0.0.1:5432/test", "postgres", "password"); Statement statement = conn.createStatement(); PreparedStatement psInsert = conn.prepareStatement(SQL_INSERT); PreparedStatement psUpdate = conn.prepareStatement(SQL_UPDATE)) { statement.execute(SQL_TABLE_DROP); statement.execute(SQL_TABLE_CREATE); // start transaction block conn.setAutoCommit(false); // default true // Run list of insert commands psInsert.setString(1, "example"); psInsert.setBigDecimal(2, new BigDecimal(10)); psInsert.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now())); psInsert.execute(); psInsert.setString(1, "kungfu"); psInsert.setBigDecimal(2, new BigDecimal(20)); psInsert.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now())); psInsert.execute(); // Run list of update commands // error, test roolback // org.postgresql.util.PSQLException: No value specified for parameter 1. psUpdate.setBigDecimal(2, new BigDecimal(999.99)); //psUpdate.setBigDecimal(1, new BigDecimal(999.99)); psUpdate.setString(2, "example"); psUpdate.execute(); // end transaction block, commit changes conn.commit(); // good practice to set it back to default true conn.setAutoCommit(true); } catch (Exception e) { e.printStackTrace(); } } //... }
出力、ステートメントは実行されず、挿入ステートメントはロールバックされます。
org.postgresql.util.PSQLException: No value specified for parameter 1. at org.postgresql.core.v3.SimpleParameterList.checkAllParametersSet(SimpleParameterList.java:257) at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:292) at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441) at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365) at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143) at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:132) at com.example.jdbc.TransactionExample.main(TransactionExample.java:41)
3. 余分な…
parameter 1
エラーを修正し、期待される結果を確認してください。
//psUpdate.setBigDecimal(2, new BigDecimal(999.99)); psUpdate.setBigDecimal(1, new BigDecimal(999.99)); psUpdate.setString(2, "example"); psUpdate.execute();
出力
2 rows are inserted and 1 row is updated.
ソースコードをダウンロード
$ git clone https://github.com/example/java-jdbc.git
$ cd postgresql