Как в Go управлять режимами работы транзакций и какие существуют уровни их изоляции?

Ответ

В Go режимы работы транзакций в пакете database/sql настраиваются с помощью структуры sql.TxOptions при её создании. Ключевые параметры — это уровень изоляции и флаг "только для чтения".

// Контекст для управления временем жизни транзакции
ctx := context.Background()

// Опции для транзакции
opts := &sql.TxOptions{
    // Уровень изоляции. sql.LevelDefault использует настройки по умолчанию для СУБД.
    Isolation: sql.LevelSerializable,
    // Флаг, указывающий, что транзакция не будет изменять данные.
    ReadOnly:  false, 
}

// Начало транзакции с заданными опциями
tx, err := db.BeginTx(ctx, opts)
if err != nil {
    log.Fatal(err)
}
// Не забудьте откатить транзакцию в случае ошибки
// tx.Commit() или tx.Rollback()

Уровни изоляции

Стандартные уровни изоляции, доступные в Go, определяют, как транзакции "видят" изменения, сделанные другими параллельными транзакциями:

  • LevelDefault: Используется уровень по умолчанию, установленный в самой базе данных.
  • LevelReadUncommitted: "Грязное чтение". Транзакция может читать незафиксированные (uncommitted) изменения других транзакций. Самый быстрый, но наименее безопасный уровень.
  • LevelReadCommitted: "Чтение зафиксированных данных". Транзакция видит только те изменения, которые уже были зафиксированы (committed). Предотвращает "грязное чтение".
  • LevelRepeatableRead: "Повторяемое чтение". Гарантирует, что при повторном чтении одних и тех же данных в рамках одной транзакции результат будет одинаковым. Предотвращает "неповторяемое чтение".
  • LevelSerializable: "Сериализуемость". Самый строгий уровень. Гарантирует, что результат параллельного выполнения транзакций будет таким же, как если бы они выполнялись последовательно. Предотвращает все аномалии, включая "фантомное чтение".

Флаг ReadOnly

Установка ReadOnly: true сообщает базе данных, что транзакция не будет вносить изменения. Некоторые СУБД могут использовать это для оптимизации производительности, например, направляя запросы на реплику для чтения.

Выбор уровня изоляции — это всегда компромисс между согласованностью данных и производительностью.