Ответ
Транзакция — это логическая единица работы с базой данных, которая состоит из последовательности одной или нескольких операций (SQL-запросов). Она выполняется по принципу «всё или ничего»: либо все её изменения фиксируются, либо все откатываются, что гарантирует целостность данных.
Свойства транзакций (ACID):
- Атомарность (Atomicity) – Транзакция выполняется полностью. При сбое все изменения откатываются.
- Согласованность (Consistency) – Транзакция переводит базу из одного валидного состояния в другое, соблюдая все правила и ограничения (constraints).
- Изолированность (Isolation) – Параллельные транзакции не должны влиять друг на друга. Степень изоляции настраивается.
- Долговечность (Durability) – После успешного завершения (commit) изменения сохраняются окончательно, даже при сбое системы.
Практический пример на Java (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); // Списываем со счета 1
stmt1.executeUpdate();
PreparedStatement stmt2 = conn.prepareStatement(
"UPDATE accounts SET balance = balance + ? WHERE id = ?"
);
stmt2.setBigDecimal(1, new BigDecimal("100.00"));
stmt2.setInt(2, 2); // Зачисляем на счет 2
stmt2.executeUpdate();
conn.commit(); // Фиксируем оба изменения
} catch (SQLException e) {
conn.rollback(); // При ошибке откатываем ВСЕ изменения транзакции
throw e;
} finally {
conn.setAutoCommit(true);
conn.close();
}
Зачем это нужно: Транзакции критически важны для финансовых операций, регистраций, инвентаризации — любых процессов, где частичное выполнение привело бы к нарушению логики и целостности данных.
Ответ 18+ 🔞
Да ты посмотри, что эти умники напридумывали! Сидят, блядь, в своих конторах, кофе пьют и думают: "А как бы нам так сделать, чтобы данные не разъебались, если что-то пойдёт не так?". И родили, сука, концепцию — транзакция.
Это, грубо говоря, такой священный пакет операций. Либо всё внутри него выполняется до конца, либо, если где-то заскрипело, — всё нахуй откатывается, как будто ничего и не было. Никаких полумер! Никаких "ой, тут списалось, а тут не зачислилось". Пиздец логике данных.
И свойства у неё, блядь, не абы какие, а ACID, как кислота разъедающая:
- Атомарность (Atomicity) – Это как, понимаешь, взорвать петарду. Либо бахнула вся, либо нихуя. Так и тут: либо транзакция прошла целиком, либо при малейшей ошибке — откат в исходное состояние, и все довольны.
- Согласованность (Consistency) – База данных — не помойка, тут правила есть. Транзакция обязана перевести базу из одного правильного состояния в другое правильное состояние. Никаких "запишу сумму, а про ограничение на отрицательный баланс забуду". Не, сука, так не пойдёт.
- Изолированность (Isolation) – Представь, два чувака одновременно лезут в один холодильник. Один тянет сосиску, второй тоже за неё хватается. Короче, драка и сосиска порвана. Чтобы такого не было, транзакции изолируют. Одна не видит промежуточного бардака от другой. Хотя степень этой изоляции можно настраивать — от "полного уединения" до "да похуй, пусть видят".
- Долговечность (Durability) – Вот это, блядь, самое жёсткое. Раз уж транзакция сказала "всё, я закончила, коммит", то её изменения высекаются в камне. Даже если сервер тут же накроется медным тазом от блэкаута, после перезагрузки данные будут целы. Записалось — пиши пропало.
Ну а теперь, блядь, смотри, как это выглядит в коде, на яве:
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();
// Пытаемся закинуть сотню на второй счёт
PreparedStatement stmt2 = conn.prepareStatement(
"UPDATE accounts SET balance = balance + ? WHERE id = ?"
);
stmt2.setBigDecimal(1, new BigDecimal("100.00"));
stmt2.setInt(2, 2);
stmt2.executeUpdate();
conn.commit(); // ВСЁ прошло гладко? Фиксируем навечно! Деньги переведены.
} catch (SQLException e) {
conn.rollback(); // Ой, что-то пошло не так? Откатываем ВСЁ нахуй! Деньги вернулись на первый счёт.
throw e;
} finally {
conn.setAutoCommit(true);
conn.close();
}
И зачем этот цирк, спросишь? Да затем, ёпта! Чтобы когда ты за пиццу платишь, деньги с твоей карты списались, а на счёт пиццерии — зачислились. А не получилось так, что ты уже голодный, а деньги твои где-то в цифровом пространстве зависли, потому что у пиццерии там constraint на размер суммы сработал. Без транзакций — это пиздец, бардак и хаос. А с ними — красота, порядок и предсказуемость, блядь.