Ответ
Для работы с транзакциями в Go используется объект *sql.Tx
, который создается из *sql.DB
.
Основной флоу работы с транзакцией:
- Начать транзакцию с помощью
db.Begin()
илиdb.BeginTx()
. - Выполнять все запросы (SELECT, INSERT, UPDATE, DELETE) через объект транзакции
tx
, а не черезdb
. - Если любая из операций завершилась ошибкой, откатить транзакцию с помощью
tx.Rollback()
. - Если все операции успешны, зафиксировать изменения с помощью
tx.Commit()
.
Пример с использованием defer
для надежности:
Этот паттерн гарантирует, что транзакция будет отменена, если что-то пойдет не так.
db, err := sql.Open("postgres", "user=... password=... dbname=... sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 1. Начинаем транзакцию
ctx := context.Background()
tx, err := db.BeginTx(ctx, nil) // Используем BeginTx для передачи контекста
if err != nil {
log.Fatal(err)
}
// 2. Откладываем Rollback. Если Commit выполнится успешно,
// Rollback вернет ошибку sql.ErrTxDone, которую можно безопасно игнорировать.
defer tx.Rollback()
// 3. Выполняем операции внутри транзакции
_, err = tx.ExecContext(ctx, "UPDATE accounts SET balance = balance - 100 WHERE id = 1")
if err != nil {
// Ошибка уже обработается в defer tx.Rollback()
log.Printf("Failed to debit account: %v", err)
return
}
_, err = tx.ExecContext(ctx, "UPDATE accounts SET balance = balance + 100 WHERE id = 2")
if err != nil {
log.Printf("Failed to credit account: %v", err)
return
}
// 4. Если все хорошо, коммитим транзакцию
if err = tx.Commit(); err != nil {
log.Fatal(err)
}
fmt.Println("Transaction committed successfully")
Важные моменты:
- Изоляция: Для установки уровня изоляции транзакции (например,
sql.LevelSerializable
) используйтеdb.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
. - Контекст: Передавайте
context.Context
вBeginTx
иExecContext
/QueryRowContext
для управления временем выполнения и отменой запросов. - Всегда используйте
tx
: Послеdb.Begin()
, все операции должны выполняться через объектtx
, чтобы они были частью одной транзакции.