Ответ
Это свойство называется Атомарность (Atomicity).
Атомарность — это один из четырех принципов ACID, который гарантирует, что любая транзакция будет зафиксирована в базе данных только в том случае, если все её операции выполнены успешно. Если хотя бы одна из операций завершается ошибкой, все изменения, сделанные в рамках этой транзакции, будут отменены (откачены).
Простой аналог — банковский перевод. Операция состоит из двух действий: списание средств с одного счета и зачисление на другой. Атомарность гарантирует, что произойдут либо оба действия, либо ни одного. Не может случиться так, что деньги списались, но не зачислились.
В Go с пакетом database/sql
это реализуется через объект sql.Tx
:
// db - это ваше подключение к базе данных (*sql.DB)
// 1. Начинаем транзакцию
tx, err := db.Begin()
if err != nil {
log.Fatalf("Failed to begin transaction: %v", err)
}
// defer tx.Rollback() — хороший паттерн для отката в случае паники или раннего return
defer tx.Rollback()
// 2. Выполняем операции в рамках транзакции
_, err = tx.Exec("UPDATE accounts SET balance = balance - 100 WHERE user_id = 1")
if err != nil {
// При ошибке Rollback будет вызван через defer
log.Printf("Failed to debit account: %v", err)
return
}
_, err = tx.Exec("UPDATE accounts SET balance = balance + 100 WHERE user_id = 2")
if err != nil {
// При ошибке Rollback будет вызван через defer
log.Printf("Failed to credit account: %v", err)
return
}
// 3. Если все успешно, фиксируем изменения
if err = tx.Commit(); err != nil {
log.Fatalf("Failed to commit transaction: %v", err)
}
// Если Commit() прошел успешно, отложенный Rollback() вернет ошибку, которую можно игнорировать.