← Назад к вопросам

Как транзакции могут блокировать друг друга?

2.0 Middle🔥 151 комментариев
#Базы данных

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизмы блокировок в транзакциях

В базах данных, поддерживающих ACID-транзакции (особенно с уровнями изоляции выше Read Uncommitted), блокировки являются основным механизмом обеспечения согласованности. Когда транзакции конкурируют за одни и те же ресурсы (строки, таблицы, индексы), возникают взаимные блокировки.

Ключевые типы блокировок

Обычно используются следующие типы блокировок:

  • Эксклюзивные (X) — для модификации данных, запрещают любые другие блокировки
  • Разделяемые (S) — для чтения данных, разрешают другие разделяемые блокировки
  • Update (U) — промежуточная блокировка для последующего обновления

Сценарии взаимной блокировки транзакций

1. Блокировка чтения-записи (Read-Write Blocking)

-- Транзакция 1
BEGIN TRANSACTION;
UPDATE users SET balance = balance + 100 WHERE id = 1;
-- Удерживает X-блокировку на строке id=1

-- Транзакция 2 (выполняется параллельно)
BEGIN TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE; -- Ждет снятия X-блокировки

2. Блокировка записи-чтения (Write-Read Blocking)

-- Транзакция 1
BEGIN TRANSACTION;
SELECT * FROM orders WHERE total > 1000 FOR UPDATE;
-- Удерживает S-блокировку на отобранных строках

-- Транзакция 2
BEGIN TRANSACTION;
UPDATE orders SET status = 'processed' WHERE total > 2000;
-- Часть строк может пересекаться, требуется X-блокировка

3. Взаимная блокировка (Deadlock)

-- Транзакция 1
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- Транзакция 2 (параллельно)
UPDATE accounts SET balance = balance - 50 WHERE id = 2;
UPDATE accounts SET balance = balance + 50 WHERE id = 1;
-- Классический deadlock при разном порядке обновления

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

Поведение блокировок сильно зависит от уровня изоляции транзакций:

  • Read Uncommitted — минимальные блокировки, возможны "грязные" чтения
  • Read Committed — строковые блокировки для изменяемых данных
  • Repeatable Read — блокировки на диапазоны строк
  • Serializable — самые строгие блокировки, включая prediсate locks

Пример на уровне кода Go (с использованием sql.Tx)

func transferFunds(db *sql.DB, from, to int, amount float64) error {
    tx, err := db.BeginTx(ctx, &sql.TxOptions{
        Isolation: sql.LevelSerializable, // Строгая изоляция
    })
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // Блокировка строки для чтения/записи
    var balance float64
    err = tx.QueryRowContext(ctx, 
        "SELECT balance FROM accounts WHERE id = $1 FOR UPDATE", 
        from).Scan(&balance)
    if err != nil {
        return err
    }

    if balance < amount {
        return errors.New("insufficient funds")
    }

    // Эти операции будут блокировать другие транзакции
    // до COMMIT или ROLLBACK
    _, err = tx.ExecContext(ctx,
        "UPDATE accounts SET balance = balance - $1 WHERE id = $2",
        amount, from)
    if err != nil {
        return err
    }

    _, err = tx.ExecContext(ctx,
        "UPDATE accounts SET balance = balance + $1 WHERE id = $2",
        amount, to)
    if err != nil {
        return err
    }

    return tx.Commit() // Освобождение всех блокировок
}

Методы предотвращения и уменьшения блокировок

  1. Оптимизация порядка операций — всегда блокируйте ресурсы в одинаковом порядке
  2. Короткие транзакции — минимизируйте время удержания блокировок
  3. Использование индексов — уменьшение количества блокируемых строк
  4. Оптимальный уровень изоляции — не используйте Serializable без необходимости
  5. Контроль таймаутов — настройка lock_timeout
  6. Row Versioning (MVCC) — в PostgreSQL и других СУБД уменьшает блокировки для чтения

Мониторинг и диагностика

Для выявления проблем с блокировками используйте:

  • pg_locks в PostgreSQL
  • sys.dm_tran_locks в SQL Server
  • INFORMATION_SCHEMA.INNODB_LOCKS в MySQL
  • Логирование длительных ожиданий блокировок

Блокировки — необходимый компромисс между согласованностью данных и параллелизмом. Правильное управление транзакциями требует глубокого понимания как бизнес-логики, так и особенностей конкретной СУБД. В высоконагруженных системах рекомендуется использовать паттерны, уменьшающие конфликты, такие как очередь задач или оптимистичные блокировки, где это допустимо.

Как транзакции могут блокировать друг друга? | PrepBro