Когда мы работаем с JDBC, то по умолчанию наше соединение работает в режиме auto-commit, это означает, что каждый SQL – запрос будет выполнен и результаты будут сохранены в таблице нашей базы данных (далее – БД).
Для простых приложений это крайне удобно. Но, если мы хотим увеличить производительность, использовать распределённые транзакции, либо интегрировать бизнес-логику, то нам необходимо выключить режим auto-commit для управления нашими транзакциями.
Транзакцию дают нам возможность контролировать когда и где сохранять изменения в БД. Благодаря этому мы, например, можем объединить группу SQL – запросов в одну логическую группу и, если один из запросов не пройдёт – мы отменяем всю транзакцию.
Для того чтобы получить доступ к управлению транзакциями, нам необходимо использовать метод setAutoCommit().
В коде это выглядит следующим образом:
connection.setAutoCommit(false);
Выполнение и откат (Commit and Rollback)
После того, как мы выполнили необходимые нам изменения, мы должны вызвать метод commit() таким образом:
connection.commit();
Если же мы хотим выполнить откат изменений, то нам необходимо вызвать метод rollback():
connection.rollback();
Точки сохранения (Savepoints)
Начиниая со спецификации JDBC 3.0 интерфейс Savepoint даёт нам ещё больший контроль над транзакциями.
Когда мы используем savepoint, мы определяем точку, до которой произойдёт откат в случае, если нам понадобится отменить изменения.
Для управления этой функцией существует два метода:
- setSavepoint (String savepointName)
Определяет новую точку сохранения и возвращает экземпляр Savepoint. - releaseSavepoint (String savepointName)
Этот метод удаляет точку сохранения. В качестве параметра этот метод принимает экземпляр Savepoint.
Для понимания того, как это работает на практике рассмотрим пример простого приложения.
Пример:
import java.sql.*;
public class SavepointDemo {
/**
* JDBC Driver and database url
*/
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DATABASE_URL = "jdbc:mysql://localhost/PROSELYTE_TUTORIALS";
/**
* User and Password
*/
static final String USER = "ВАШЕ_ИМЯ_ПОЛЬЗОВАТЕЛЯ";
static final String PASSWORD = "ВАШ_ПАРОЛЬ";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
connection.setAutoCommit(false);
statement = connection.createStatement();
String SQL;
SQL = "SELECT * FROM developers";
ResultSet resultSet = statement.executeQuery(SQL);
System.out.println("Retrieving data from database...");
System.out.println("\nDevelopers:");
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String specialty = resultSet.getString("specialty");
int salary = resultSet.getInt("salary");
System.out.println("\n================\n");
System.out.println("id: " + id);
System.out.println("Name: " + name);
System.out.println("Specialty: " + specialty);
System.out.println("Salary: $" + salary);
}
System.out.println("\n===========================\n");
System.out.println("Creating savepoint...");
Savepoint savepointOne = connection.setSavepoint("SavepointOne");
try {
SQL = "INSERT INTO developer VALUES (6, 'John','C#', 2200)";
statement.executeUpdate(SQL);
SQL = "INSERT INTO developers VALUES (7, 'Ron', 'Ruby', 1900)";
statement.executeUpdate(SQL);
connection.commit();
} catch (SQLException e) {
System.out.println("SQLException. Executing rollback to savepoint...");
connection.rollback(savepointOne);
}
SQL = "SELECT * FROM developers";
resultSet = statement.executeQuery(SQL);
System.out.println("Retrieving data from database...");
System.out.println("\nDevelopers:");
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String specialty = resultSet.getString("specialty");
int salary = resultSet.getInt("salary");
System.out.println("id: " + id);
System.out.println("Name: " + name);
System.out.println("Specialty: " + specialty);
System.out.println("Salary: $" + salary);
System.out.println("\n================\n");
}
System.out.println("Closing connection and releasing resources...");
resultSet.close();
statement.close();
connection.close();
}
}
В результате работы программы мы получим, примерно, следующий результат:
/*Some System Messages*/
Retrieving data from database...
Developers:
================
id: 1
Name: Proselyte
Specialty: Java
Salary: $3000
================
id: 2
Name: Peter
Specialty: C++
Salary: $4000
================
id: 3
Name: AsyaSmile
Specialty: UI/UX
Salary: $3000
================
id: 4
Name: Eugene
Specialty: Java
Salary: $4000
================
id: 5
Name: Mike
Specialty: PHP
Salary: $2500
===========================
Как мы видим, в этом приложении мы добавляем две записи с помощью двух SQL – запросов. Первый запрос корректен и выполняется без проблем. Второй же запрос содержит синтаксические ошибки и программа выдаёт нам SQLException.
Но метод commit() мы вызываем только после второго запроса. Поэтому, после выполнения отката, мы получаем таблицу в исходном виде, так как первый запрос также был отменён.
В этом уроке мы изучили основы управления транзакциями и рассмотрели пример с применением методов commit(), rollback() и использованием точки сохранения (savepoint).
В следующем уроке мы изучим исключения и их обработку при работе с JDBC.