Транзакция JDBC убедитесь, что набор инструкций SQL выполняется как единое целое, либо все инструкции выполняются успешно, либо НИ одна из инструкций не выполняется (откат всех изменений).
1. Без транзакции JDBC
1.1 Пример JDBC для вставки двух строк и обновления одной строки.
package com.mkyong.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, "mkyong"); 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, "mkyong"); 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.mkyong.jdbc.TransactionExample.main(TransactionExample.java:41)
2. Использование транзакции JDBC
2.1 Чтобы включить транзакцию, установите для автоматической фиксации значение 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 Тот же пример с транзакцией JDBC.
package com.mkyong.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, "mkyong"); 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, "mkyong"); 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.mkyong.jdbc.TransactionExample.main(TransactionExample.java:41)
3. Дополнительный…
Исправьте ошибку параметр 1
и посмотрите ожидаемый результат.
//psUpdate.setBigDecimal(2, new BigDecimal(999.99)); psUpdate.setBigDecimal(1, new BigDecimal(999.99)); psUpdate.setString(2, "mkyong"); psUpdate.execute();
Выход
2 rows are inserted and 1 row is updated.
Скачать Исходный Код
Рекомендации
- Использование транзакции
- Учебные пособия по Java JDBC
- JDBC Подготовленное утверждение – Пакетное обновление
- Пакетное обновление Spring JdbcTemplate() Пример
Оригинал: “https://mkyong.com/jdbc/jdbc-transaction-example/”