Топ-100Транзакции в SQL и JDBC - CodOrbits
LogoCodOrbits

Раздел: JDBC

Научитесь подключаться к базам данных через JDBC, выполнять SQL-запросы и обрабатывать результаты в Java.

Все разделы
Иконка JDBC

Транзакции в SQL и JDBC

Last updated: 9 мая 2025 г.

Представим, есть некоторая последовательность SQL запросов, которые должны последовательно выполняться.

Если на определенном запросе возникнет ошибка, часто бывает, что необходимо откатить уже выполненные перед этим запросы.

Такое бывает необходимо когда набор последовательных SQL запросов связаны по смыслу, то есть без выполнения одного из запросов из этого набора нет смысла вы выполнении всех остальных. Очевидно, что если какой-то из запросов в наборе не выполнился, остальные, которые выполнились перед ним необходимо откатить. Набор связанных запросов называют транзакцией.

Управление транзакциями реализуется спец. методами класса Connection и доп. классом SavePoint

Пример программы:

1import java.sql.*;
2public class Transactions {
3    public static void main(String[] args)
4        throws ClassNotFoundException, SQLException {
5        Class.forName("com.mysql.cj.jdbc.Driver");
6        Connection connection =
7            DriverManager.getConnection(
8                "jdbc:mysql://localhost/storage",
9                "root", "07998MSD");
10        Statement statement = connection.createStatement();
11
12        //Строка кода ниже отменяет автоматическое выполнение
13        //каждой sql команды по отдельности. теперь они все
14        //будут выполнены только после вызова connection.commit()
15        connection.setAutoCommit(false);
16        try {
17            statement.executeUpdate("INSERT INTO books "
18                +"(name,author) VALUES (‘Book1’, ‘Author1’);");
19            statement.executeUpdate("INSERT INTO books "
20                +"(name,author) VALUES (‘Book2’, ‘Author2’);");
21            statement.executeUpdate("INSERT INTO books "
22                +"(name,author) VALUES (‘Book3’, ‘Author3’);");
23            statement.executeUpdate("INSERT INTO books "
24                +"(name,author) VALUES (‘Book4’, ‘Author4’);");
25            statement.executeUpdate("INSERT INTO books "
26                +"(name,author) VALUES (‘Book5’, ‘Author5’);");
27
28            //если ошибок не возникало методом commit
29            //последовательно выполнятся все запросы выше
30            connection.commit();
31        }
32        catch (SQLException e) {
33            //Если возникла ошибка на каком-то из запросов выше
34            //то происходит переход сюда в catch
35            //метод commit при этом не произойдет так как мы видим
36            //выше что он после запросов).
37
38            //Метод rollback отменяет те запросы, в которых
39            //не было ошибок, которые были
40            //перед запросом, в котором ошибка произошла.
41            //Важно отметить что эти самые запросы, в которых не
42            //было ошибок еще не повлияли на БД, то есть они
43            //еще не случились, они случатся когда произойдет
44            //следующий commit.
45            //То есть например если в третьем
46            //по счету запросе произойдет ошибка и иза этого
47            //вызовется catch и перед rollback ниже мы вызовем
48            //метод commit то произойдет вставка в базу данных
49            //Book1 и Book2, то есть случатся первый
50            //и второй запрос и rollback уже ничего не сделает.
51            //Если же мы вызовем commit после rollback, а не перед
52            //ним то rollback отменит первый и второй запрос и
53            //они уже случатся при следующем commit то есть том,
54            //который после rollback так как rollback отменил их.
55            connection.rollback();
56            //Также важно заметить что
57            //отменяются только изменения UPDATE и INSERT
58        }
59        statement.close();
60        connection.close();
61    }
62}

Скомпилируем, запустим программу и проверим таблицу books через MySQL консоль:

Видим, что в таблицу успешно добавились все запросы, так как в них не было ошибок.

Продемонстрируем те случаи, которые были описаны перед rollback в коде выше.

Для начала удалим те 5 книг, которые были добавлены в таблицу выше.

Теперь давайте сделаем так, чтобы в третьем запросе случилась ошибка и перед rollback сделаем commit.

Пример программы:

1import java.sql.*;
2
3public class Transactions {
4    public static void main(String[] args)
5        throws ClassNotFoundException, SQLException {
6        Class.forName("com.mysql.cj.jdbc.Driver");
7        Connection connection =
8            DriverManager.getConnection(
9                "jdbc:mysql://localhost/storage",
10                "root", "07998MSD");
11        Statement statement = connection.createStatement();
12
13        connection.setAutoCommit(false);
14        try {
15            statement.executeUpdate("INSERT INTO books "
16                +"(name,author) VALUES (‘Book1’, ‘Author1’);");
17            statement.executeUpdate("INSERT INTO books "
18                +"(name,author) VALUES (‘Book2’, ‘Author2’);");
19            // на запросе ниже случится ошибка и переход в catch
20            statement.executeUpdate("INSERT INTO books "
21                +"(name,author) VALUES (‘Book3’, ‘Author3’, ‘str’);");
22            statement.executeUpdate("INSERT INTO books "
23                +"(name,author) VALUES (‘Book4’, ‘Author4’);");
24            statement.executeUpdate("INSERT INTO books "
25                +"(name,author) VALUES (‘Book5’, ‘Author5’);");
26
27            connection.commit();
28        } catch (SQLException e) {
29            // коммитим первый и второй запрос
30            connection.commit();
31            // rollback уже ничего не сделает
32            connection.rollback();
33        }
34        statement.close();
35        connection.close();
36    }
37}

Скомпилируем, запустим программу и проверим таблицу books через MySQL консоль:

Видим, что выполнился только первый и второй запрос.

Смысл транзакций теперь должен быть придельно понятен. Все запросы, в которых не было ошибок случаются с помощью commit, а rollback отменяет запросы, которые можно было бы закоммитить.

Давайте опять удалим те книги, которые были ранее добавлены в таблицу.

Теперь давайте сделаем так, чтобы в третьем запросе случилась ошибка и теперь сделаем сommit после rollback.

Пример программы:

1import java.sql.*;
2public class Transactions {
3    public static void main(String[] args)
4        throws ClassNotFoundException, SQLException {
5        Class.forName("com.mysql.cj.jdbc.Driver");
6        Connection connection =
7            DriverManager.getConnection(
8                "jdbc:mysql://localhost/storage",
9                "root", "0799MSD");
10        Statement statement = connection.createStatement();
11
12        connection.setAutoCommit(false);
13        try {
14            statement.executeUpdate("INSERT INTO books "
15                +"(name,author) VALUES (‘Book1’, ‘Author1’);");
16            statement.executeUpdate("INSERT INTO books "
17                +"(name,author) VALUES (‘Book2’, ‘Author2’);");
18            //на запросе ниже случится ошибка и переход в catch
19            statement.executeUpdate("INSERT INTO books "
20                +"(name,author) VALUES (‘Book3’, ‘Author3’, ‘str’);");
21            statement.executeUpdate("INSERT INTO books "
22                +"(name,author) VALUES (‘Book4’, ‘Author4’);");
23            statement.executeUpdate("INSERT INTO books "
24                +"(name,author) VALUES (‘Book5’, ‘Author5’);");
25
26            connection.commit();
27        }
28        catch (SQLException e) {
29            //rollback отменит не два запроса которые
30            //могли бы случиться если бы мы вызвали
31            //commit перед rollback
32            connection.rollback();
33            //commit теперь ничего не сделает
34            connection.commit();
35        }
36        statement.close();
37        connection.close();
38    }
39}

Скомпилируем, запустим программу и проверим таблицу books через MySQL консоль:

Видим, что в таблицу ничего не добавилось, так как rollback отменил те два запроса, которые можно было бы закоммитить.


Следующие уроки

Savepoint в JDBC транзакциях

13
мин.

Similar Articles Icon
Divider

Изоляция транзакций. Грязное чтение

15
мин.

Similar Articles Icon
Divider

Изоляция транзакций. Неповторяющееся чтение

15
мин.

Similar Articles Icon