Что такое транзакции в базах данных и каковы их свойства?

Ответ

Транзакция — это последовательность операций с базой данных, которая выполняется как единая, неделимая (атомарная) единица работы. Она гарантирует, что все операции либо будут успешно выполнены и зафиксированы (COMMIT), либо, в случае сбоя, полностью отменены (ROLLBACK), возвращая систему в исходное состояние.

Это обеспечивает целостность данных. Классический пример — банковский перевод: списание средств с одного счета и зачисление на другой должны произойти вместе или не произойти вовсе.

Основные свойства транзакций описываются акронимом ACID:

  • Atomicity (Атомарность): Гарантирует, что транзакция выполняется по принципу "всё или ничего".
  • Consistency (Согласованность): Транзакция переводит базу данных из одного согласованного состояния в другое. Все правила и ограничения (constraints) должны быть соблюдены.
  • Isolation (Изолированность): Параллельно выполняющиеся транзакции не должны влиять друг на друга. Результат их одновременного выполнения должен быть таким же, как если бы они выполнялись последовательно.
  • Durability (Долговечность): Если транзакция успешно завершена, ее результаты должны быть сохранены и не могут быть потеряны даже в случае сбоя системы (например, отключения питания).

Упрощенный пример на Python с sqlite3:

import sqlite3

# Используем 'with' для автоматического закрытия соединения
with sqlite3.connect('bank.db') as conn:
    cursor = conn.cursor()
    sender_id = 1
    receiver_id = 2
    amount = 100

    try:
        # Списание средств со счета отправителя
        cursor.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", (amount, sender_id))
        # Зачисление средств на счет получателя
        cursor.execute("UPDATE accounts SET balance = balance + ? WHERE id = ?", (amount, receiver_id))

        # Если обе операции успешны, фиксируем транзакцию
        conn.commit()
        print("Перевод успешно выполнен.")

    except sqlite3.Error as e:
        # При любой ошибке откатываем все изменения
        conn.rollback()
        print(f"Ошибка! Транзакция отменена: {e}")

Ответ 18+ 🔞

А, ну вот, смотри, объясняю на пальцах, как для дебила, но ты не обижайся, я сам такой был. Транзакция — это, блядь, такая пачка операций, которую ты либо делаешь всю целиком, либо нихуя не делаешь. Как будто ты в магазине набрал продуктов, а на кассе карта не сработала. Так вот, либо ты всё оплатил и унёс, либо, сука, всё обратно на полки расставил и ушёл с пустыми руками. Никакого «половину купил, половину вернул» — нихуя!

Зачем это? Ну представь, ты переводишь бабки с карты на карту. Твои сто рублей списались, а у тётки на счёт нихуя не пришли. Где они? В небытии, в цифровом аду зависли. Вот чтобы такого пиздеца не было, и нужны транзакции. Либо списалось И зачислилось, либо нихуя не двигалось. Это и есть целостность, ёпта!

А теперь держись за стул, потому что есть такая хуйня под названием ACID. Это не кислота, а четыре буквы, которые спасают от ебалы.

  1. A — Атомарность (Atomicity). Это я уже объяснил. Всё или ничего. Как пиздец.
  2. C — Согласованность (Consistency). База данных — не помойка. В ней есть правила. «Баланс не может быть отрицательным», «ID должен быть уникальным». Так вот, транзакция обязана эти правила соблюсти. Не можешь — вали нахуй, откат.
  3. I — Изолированность (Isolation). Представь, что ты и твой кореш одновременно лезете в один и тот же ящик с деньгами. Начнётся драка, порвутся купюры. Изоляция — это когда вы лезете по очереди, или там ставят перегородки, чтобы вы друг другу не мешали. Результат должен быть такой, будто вы делали всё по одному, даже если делали впятером.
  4. D — Долговечность (Durability). Ну вот ты транзакцию сделал, деньги перевёл. И тут, блядь, свет вырубили, сервер упал. Так вот, когда его включат обратно, твой перевод должен быть там, записанный в каменную скрижаль, а не испарившийся, как твои надежды на повышение. Это и есть долговечность — закоммитил и забыл.

А вот тебе пример кода, чтобы вообще всё встало на свои места. Смотри, как это выглядит в жизни:

import sqlite3

# Используем 'with' для автоматического закрытия соединения
with sqlite3.connect('bank.db') as conn:
    cursor = conn.cursor()
    sender_id = 1
    receiver_id = 2
    amount = 100

    try:
        # Списание средств со счета отправителя
        cursor.execute("UPDATE accounts SET balance = balance - ? WHERE id = ?", (amount, sender_id))
        # Зачисление средств на счет получателя
        cursor.execute("UPDATE accounts SET balance = balance + ? WHERE id = ?", (amount, receiver_id))

        # Если обе операции успешны, фиксируем транзакцию
        conn.commit()
        print("Перевод успешно выполнен.")

    except sqlite3.Error as e:
        # При любой ошибке откатываем все изменения
        conn.rollback()
        print(f"Ошибка! Транзакция отменена: {e}")

Видишь? В try мы пытаемся сделать две штуки: списать и зачислить. Если где-то посередине случится пиздец (например, у отправителя денег нет), то мы летим в except и делаем rollback. И база откатывается назад, как будто мы нихуя и не начинали. А если всё прошло гладко — commit, и все изменения намертво прибиваются гвоздями. Вот и вся магия, ебать её в сраку.