Java commit rollback transaction

Управление транзакциями, commit rollback

Транзакция Transaction включает одно или несколько изменений в базе данных, которые после выполнения либо все фиксируются (commit), либо все откатываются назад (rollback). При вызове метода commit или rollback текущая транзакция заканчивается и начинается другая.

По умолчанию каждое новое соединение находится в режиме автофиксации (autocommit = true). Это означает автоматическую фиксацию (commit) транзакции после выполнения каждого запроса. В этом случае транзакция включает только одно изменение (один запрос).

Если autocommit запрещен, т.е. равен false, то транзакция не заканчивается до явного вызова commit или rollback, включая, таким образом, все выражения, выполненные с момента последнего вызова commit или rollback. В этом случае все SQL-запросы в транзакции фиксируются или откатываются группой.

Метод фиксации commit завершает все изменения в БД, проделанные SQL-выражением, и снимает также все блокировки, установленные транзакцией. Метод rollback наоборот — не сохранит изменения и восстановит исходное состояние на момент начала транзакции.

Иногда пользователю нужно, чтобы какое-либо изменение не вступило в силу до тех пор, пока не вступит в силу предыдущее изменение. Этого можно достичь запрещением autocommit и группировкой обоих запросов в одну транзакцию. Если оба изменения произошли успешно, то вызывается метод commit, который переносит эффект от этих изменений в БД; если одно или оба запроса не прошли, то вызывается метод rollback, который возвращает прежнее состояние БД.

Большинство JDBC-драйверов поддерживают транзакции. В действительности драйвер, соответствующий спецификации JDBC, обязан поддерживать их. Интерфейс DatabaseMetaData позволяет получить информацию об уровнях изолированности транзакций, которые поддерживаются данной СУБД.

Пример использования транзакции — commit, autocommit

Connection connection = . ; // Сброс автофиксации connection.setAutoCommit(false); // Первая транзакция PreparedStatement updateSales = connection.prepareStatement( "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?"); updateSales.setInt(1, 50); updateSales.setString(2, "Colombian"); updateSales.executeUpdate(); // Вторая транзакция PreparedStatement updateTotal = connection.prepareStatement( "UPDATE COFFEES SET TOTAL = TOTAL + ? WHERE COF_NAME LIKE ?"); updateTotal.setInt(1, 50); updateTotal.setString(2, "Colombian"); updateTotal.executeUpdate(); // Завершение транзакции connection.commit(); // Восстановление по умолчанию connection.setAutoCommit(true);

В примере для соединения Connection режим автофиксации отключен и два оператора updateSales и updateTotal будут зафиксированы вместе при вызове метода commit.

В последней строке примера режим автофиксации autocommit восстанавливается. То есть, каждый следующий запрос опять будет фиксироваться автоматически после своего завершения.

Желательно запрещать режим автофиксации только тогда, когда в транзакции участвуют данные из нескольких таблиц, чтобы связанные данные нескольких таблиц либо были все записаны, либо отменены.

Уровни изолированности транзакций, dirty read

Транзакции не только обеспечивают полное завершение или откат операторов, которые они охватывают, но также изолируют данные. Уровень изоляции описывает степень видимости измененных данных для других транзакций.

Допустим, что один из пользователей обновляет параметры заказчика (адрес, телефон, email) и программа требует подтверждения выполнения транзакции. В это же время другой пользователь читает информацию из базы данных о данном заказчике. Прочитает ли второй пользователь новые и не подтвержденные данные, или будет читать старые? Ответ зависит от уровня изоляции транзакции. Если транзакция разрешает другим программам читать не подтвержденные данные, то другая программа не будет ожидать окончания транзакции. Но здесь возникает компромисс — если транзакция будет отменена, то вторая другая программа может прочитать ошибочные данные.

Читайте также:  Replace all space in string java

Есть несколько способов разрешения конфликтов между одновременно выполняющимися транзакциями. Разработчик может определить уровень изолированности так, что пока одна транзакция изменяет какое-либо значение, вторая транзакция могла бы прочитать обновленное значение до того, пока первая не выполнит commit или rollback. Для этого следует установить уровень изолированности TRANSACTION_READ_UNCOMMITTED:

Connection connection; . connection.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);

В данном коде серверу указано на возможность чтения измененных значений до того, как выполнится commit, т.е. определена возможность «грязного чтения» («dirty read«).

По умолчанию уровень изоляции транзакций обычно установлен в READ_COMMITED.

Изменение уровня изолированности во время транзакции нежелательно, так как произойдет автоматический вызов commit, что повлечет за собой фиксацию изменений.

В связи с тем, что уровни изоляции, предлагаемые различными поставщиками СУБД, могут меняться, Вам следует обратиться к документации за дополнительной информацией. Уровни изоляции не стандартизованы для платформы J2EE.

Чем выше уровень изолированности транзакций, тем больше внимания СУБД уделяет устранению конфликтов. Интерфейс Connection определяет пять таких уровней. Минимальный из них соответствует случаю, когда транзакции не поддерживаются вовсе, а максимальный — невозможности существования более одной транзакции в любой момент времени.

Обычно, чем выше уровень изолированности, тем медленнее выполняется приложение (из-за избыточной блокировки). При выборе конкретного уровня изолированности разработчик должен найти золотую середину между потребностями в производительности и требованиями к целостности данных. Очевидно, что реально поддерживаемые уровни зависят от возможностей используемой СУБД.

При создании объекта Connection уровень его изолированности зависит от драйвера или БД. Можно вызвать метод setIsolationLevel, чтобы изменить уровень изолированности транзакций, и новое значение уровня будет установлено до конца сессии. Чтобы установить уровень изолированности только для одной транзакции, надо установить его перед выполнением транзакции и восстановить прежнее значение после ее завершения.

Типы уровней изолированности

  • TRANSACTION_NONE
    Транзакции не поддерживаются.
  • TRANSACTION_READ_COMMITTED
    Запрет на «грязное чтение» (dirty read). Данный уровень блокирует транзакциям чтение строк с неподтвержденными изменениями в них.
  • TRANSACTION_READ_UNCOMMITTED
    Разрешение на «dirty read». Данный уровень позволяет изменять строку с помощью одной транзакции и прочесть ее другой прежде, чем изменения в этой строке будут подтверждены (dirty read). Если изменения будут отменены с помощью rollback(), вторая транзакция вернет неправильную строку.
  • TRANSACTION_REPEATABLE_READ
    Запрет на «dirty read». Данный уровень препятствует транзакции от чтения строки с неподтвержденным изменением в ней, он также предотвращает ситуацию, когда одна транзакция читает строку, а вторая транзакция изменяет ее, при этом первая транзакция перечитывая строку, получает разные значения каждый раз (разовое чтение).
  • TRANSACTION_SERIALIZABLE
    Запрет на «dirty read». Данный уровень включает предотвращения из TRANSACTION_REPEATABLE_READ, более того предотвращает ситуацию, когда одна транзакция читает все строки, которые удовлетворяют условию WHERE, а вторая транзакция вставляет строку, которая удовлетворяет тому же условию WHERE, и первая транзакция, перечитывая с тем же условием, получает дополнительную «фантомную» строку при втором чтении.

Источник

JDBC Transaction Tutorial: Commit() and Rollback() Example

Transaction Management works great when you need to execute set of task and each task executes when previous task completes. Transaction Management ensures that all the task executes successfully and if one task fails, the whole task would be rollback to previous state. Simply, either all the statements are executed, or none of the statements is executed.

Читайте также:  php-generated 503

Fact About Transaction

1. ACID: It represents ACID Properties.

Consistency ensures bringing the database from one consistent state to another consistent state.

Isolation ensures that transaction is isolated from other transaction.

Durability means once a transaction has been committed, it will remain so, even in the event of errors, power loss etc.

2. Disable Auto Commit Mode: When the connection is created it is auto commit mode. It means all the individual SQL Statements will be treated as Transaction. When using Transaction, Disable Auto Commit Mode and call it explicitly. After disabling commit mode, no statement will be execute until you call Commit() method explicitly. Each statement will be executed after the previous call of Commit method.

con.setAutoCommit(false);

In JDBC, Connection interface provides methods to manage transaction.

Method Description
void setAutoCommit (boolean status) It is true bydefault means each transaction is committed bydefault.
void commit() commits the transaction.
void rollback() cancels the transaction.

Advantage of Transaction Management

1. Transaction Management widely used in financial application where you want to ensure that if any problem happens meanwhile the payment process, the whole transaction rollback.
2. Transaction Management is also very beneficial when you need to insert multiple row in multiple table simultaneously. It ensures that all the table gets successful execution of statement and if any table fails to execute statement, all the row roll backed and none of table affected.
3. Transaction Treats all the SQL statements as a single logical unit and if one statement fails the entire transaction fails.
4. Commit and Rollback : Commit() method does the changes in database table and Rollback methods undo all the changes done by current connection con.

Programming Example

In this programming example, I will insert two row in a two different table using Transaction. This example explains Commit() method. In the next example you will get Rollback.

Step 1. Create Two Tables table1 and table2 with following description

CREATE TABLE Table1 ( ID int(11) NOT NULL AUTO_INCREMENT, PRODUCT varchar(50) NULL, PRICE varchar(10) NULL, PRIMARY KEY(ID) ) CREATE TABLE Table2( ID int(11) NOT NULL AUTO_INCREMENT, PRODUCT varchar(50) NULL, PRICE varchar(10) NULL, PRIMARY KEY(ID) )

You can use your own table to execute query. If you don’t have any, then create table using above query.

package AdvanceJDBC; import java.sql.*; public class Transaction_Example < static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String dburl = "jdbc:mysql://localhost/STOREDB"; static final String dbuser = "root"; static final String dbpass = "root"; public static void main(String[] args) < Connection con = null; Statement stmt = null; try < //Step 1 : Connecting to server and database con = DriverManager.getConnection(dburl, dbuser, dbpass); con.setAutoCommit(false); //Step 2 : Initialize Statement stmt=con.createStatement(); //Step 3 : SQL Query String query1="INSERT INTO Table1(PRODUCT,PRICE) VALUES('Laptop','29000')"; String query2="INSERT INTO Table2(PRODUCT,PRICE) VALUES('Mouse','305')"; stmt.executeUpdate(query1); stmt.executeUpdate(query2); //If you run this program without con.commit you will notice that there is no insert in table1 and table2 con.commit(); System.out.println("Row Inserted"); >catch (SQLException e) < System.err.println("Cannot connect ! "); e.printStackTrace(); >finally < System.out.println("Closing the connection."); if (con != null) try < con.close(); >catch (SQLException ignore) <> > > >

Row Inserted
Closing the connection

Читайте также:  Typescript тип стрелочной функции

Rollback Example

In this example I will use Rollback method to ensure all the successful insertion in both table. You will see what happen when statement execution fails in table 2.

Example 1: With Commit(false)

In this program I have Passed long value in PRICE column for table2. It will raise exception because of size of PRICE is set to varchar(10). This is for showing you what happened when one query executed but another get failed in transaction. You will notice that there were no changes in table.

package AdvanceJDBC; import java.sql.*; public class Rollback_Example < static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String dburl = "jdbc:mysql://localhost/STOREDB"; static final String dbuser = "root"; static final String dbpass = "root"; public static void main(String[] args) throws SQLException < Connection con = null; Statement stmt = null; try < //Step 1 : Connecting to server and database con = DriverManager.getConnection(dburl, dbuser, dbpass); con.setAutoCommit(false); //Step 2 : Initialize Statement stmt=con.createStatement(); //Step 3 : SQL Query String query1="INSERT INTO Table1(PRODUCT,PRICE) VALUES('Mobile','11500')"; stmt.executeUpdate(query1); System.out.println("Table1 Successfull"); String query2="INSERT INTO Table2(PRODUCT,PRICE) VALUES('Charger','3055241234534')"; stmt.executeUpdate(query2); //If you run this program without con.commit you will notice that there is no insert in table1 and table2 con.commit(); System.out.println("Row Inserted"); >catch (SQLException e) < System.err.println("Cannot connect ! "); con.rollback(); e.printStackTrace(); >finally < System.out.println("Closing the connection."); if (con != null) try < con.close(); >catch (SQLException ignore) <> > > >

Output
Table1 Successfull
Cannot connect !
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column ‘PRICE’ at row 1

Table 1Table 2

Example 2: Without Commit() method or Commit(true)

See this example. In this example I haven’t set Commit(false) so when the program executes query, first statement successfully inserted but raise exception in second statement. It is because I have passed more than 10 character long in PRICE that is set to varchar(10) only.

package AdvanceJDBC; import java.sql.*; public class Rollback_Example < static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String dburl = "jdbc:mysql://localhost/STOREDB"; static final String dbuser = "root"; static final String dbpass = "root"; public static void main(String[] args) throws SQLException < Connection con = null; Statement stmt = null; try < //Step 1 : Connecting to server and database con = DriverManager.getConnection(dburl, dbuser, dbpass); con.setAutoCommit(true); //Step 2 : Initialize Statement stmt=con.createStatement(); //Step 3 : SQL Query String query1="INSERT INTO Table1(PRODUCT,PRICE) VALUES('Mobile','11500')"; stmt.executeUpdate(query1); System.out.println("Table1 Successfull"); String query2="INSERT INTO Table2(PRODUCT,PRICE) VALUES('Charger','3055241234534')"; stmt.executeUpdate(query2); //If you run this program without con.commit you will notice that there is no insert in table1 and table2 con.commit(); System.out.println("Row Inserted"); >catch (SQLException e) < System.err.println("Cannot connect ! "); //con.rollback(); e.printStackTrace(); >finally < System.out.println("Closing the connection."); if (con != null) try < con.close(); >catch (SQLException ignore) <> > > >

Table1 Successfull
Cannot connect !
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column ‘PRICE’ at row 1

Table 1Table 2

Summary

In this tutorial you learned what is Transaction Management in JDBC and how to use it in Programming. The Commit(false) ensures all the successful execution of statement. If any of them not execute, the whole process gets failed. Rollback() method reverse all the changes that is made by current connection.

Источник

Оцените статью