Ответ
Транзакции — это механизм, гарантирующий корректное выполнение группы операций с данными, даже в условиях сбоев или параллельного доступа. Их важность определяется ACID-свойствами.
ACID-свойства:
-
Атомарность (Atomicity): Транзакция выполняется как единое целое. Либо выполняются все ее операции, либо ни одна. При сбое (ошибка в коде, отключение питания) система выполняет откат (ROLLBACK) всех изменений.
- Почему важно: Предотвращает частичное обновление данных (например, списание денег без их зачисления получателю).
-
Согласованность (Consistency): Транзакция переводит базу данных из одного валидного состояния в другое. Ограничения целостности (UNIQUE, FOREIGN KEY, CHECK) не нарушаются.
- Почему важно: Гарантирует, что бизнес-правила и логические инварианты данных всегда соблюдаются.
-
Изолированность (Isolation): Параллельно выполняемые транзакции не влияют друг на друга. Их эффекты изолированы. Уровни изоляции (Read Committed, Repeatable Read, Serializable) определяют степень этой изоляции, балансируя между целостностью и производительностью.
- Почему важно: Предотвращает аномалии параллельного доступа: грязное чтение, неповторяющееся чтение, фантомное чтение.
-
Долговечность (Durability): После успешного завершения транзакции (COMMIT) ее изменения сохраняются в базе данных навсегда, даже в случае последующего сбоя системы.
- Почему важно: Гарантирует, что подтвержденные данные (например, оплаченный заказ) не будут потеряны.
Пример на JDBC, демонстрирующий атомарность и откат:
Connection conn = dataSource.getConnection();
try {
conn.setAutoCommit(false); // Начало транзакции
PreparedStatement stmt1 = conn.prepareStatement(
"UPDATE accounts SET balance = balance - ? WHERE id = ?");
stmt1.setBigDecimal(1, new BigDecimal("100.00"));
stmt1.setInt(2, 1);
stmt1.executeUpdate(); // Списание со счета 1
PreparedStatement stmt2 = conn.prepareStatement(
"UPDATE accounts SET balance = balance + ? WHERE id = ?");
stmt2.setBigDecimal(1, new BigDecimal("100.00"));
stmt2.setInt(2, 2);
stmt2.executeUpdate(); // Зачисление на счет 2
conn.commit(); // Фиксация ТОЛЬКО если обе операции успешны
System.out.println("Transfer completed.");
} catch (SQLException e) {
// При ЛЮБОЙ ошибке откатываем обе операции
if (conn != null) {
conn.rollback();
System.out.println("Transfer failed. Rollback executed.");
}
} finally {
if (conn != null) conn.close();
}
Без транзакций возможны катастрофические последствия: потеря данных, финансовые ошибки, нарушение целостности связей между таблицами.