Что такое ACID в контексте баз данных? Расшифруйте и объясните каждый принцип.

Ответ

ACID — это акроним, описывающий четыре ключевых свойства, которые гарантируют надежность транзакций в базах данных.

  1. Atomicity (Атомарность)

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

    • Транзакция переводит базу данных из одного согласованного (валидного) состояния в другое. Все правила и ограничения (constraints, triggers) базы данных должны быть соблюдены. Данные не могут оказаться в противоречивом состоянии.
  3. Isolation (Изолированность)

    • Параллельно выполняющиеся транзакции не должны влиять друг на друга. Результат их одновременной работы должен быть таким же, как если бы они выполнялись последовательно. Для управления этим поведением существуют уровни изоляции транзакций (например, Read Committed, Serializable).
  4. Durability (Долговечность)

    • Если транзакция успешно завершена (COMMIT), ее результаты должны быть сохранены и не могут быть потеряны, даже в случае сбоя системы (например, отключения питания). Обычно это достигается за счет записи в журнал транзакций (WAL).

Пример транзакции в Go с database/sql:

// db - это ваше соединение с БД (*sql.DB)
tx, err := db.Begin()
if err != nil {
    log.Fatal(err)
}

// Попытка перевести 100 единиц со счета 1 на счет 2
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE id = 1")
if err != nil {
    // Если первая операция не удалась, откатываем транзакцию
    tx.Rollback()
    return
}

_, err = tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE id = 2")
if err != nil {
    // Если вторая операция не удалась, откатываем транзакцию, отменяя и первую
    tx.Rollback()
    return
}

// Если все операции успешны, подтверждаем транзакцию
err = tx.Commit()
if err != nil {
    log.Fatal(err)
}