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

Что такое блокировка в транзакции?

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

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

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

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

Что такое блокировка в транзакции?

Блокировка в контексте транзакций — это механизм управления параллельным доступом к данным в системах баз данных, который гарантирует корректность операций при одновременной работе нескольких пользователей или процессов. Основная цель блокировок — предотвратить конфликтные ситуации, такие как потерянные обновления (lost updates), "грязное" чтение (dirty reads) или неповторяемое чтение (non-repeatable reads), обеспечивая изоляцию транзакций в соответствии с уровнями изоляции ACID (Isolation).

Типы блокировок и их применение

Блокировки можно классифицировать по нескольким критериям:

  1. По уровню гранулярности:

    • Строковые блокировки: Блокируется только одна запись (строка) в таблице. Наиболее распространены в современных СУБД (например, MySQL/InnoDB, PostgreSQL).
    • Табличные блокировки: Блокируется вся таблица, что упрощает управление, но снижает параллелизм.
    • Блокировки страниц или индексов: Промежуточный вариант, например, блокировка страницы памяти или узла индекса.
  2. По типу доступа:

    • Разделяемые блокировки (Shared Locks): Позволяют нескольким транзакциям читать данные, но запрещают изменение заблокированных записей другими транзакциями. Применяются при операциях SELECT.
    • Эсклюзивные блокировки (Exclusive Locks): Запрещают любое взаимодействие с заблокированными данными (чтение и запись) со стороны других транзакций. Используются при INSERT, UPDATE, DELETE.
    • Блокировки намерения (Intent Locks): Указывают на намерение заблокировать данные на более низком уровне (например, строку), чтобы СУБД могла эффективно управлять блокировками на разных уровнях.

Практический пример в SQL и PHP

Рассмотрим сценарий банковского перевода, где без блокировок возможны конфликты. Допустим, две транзакции одновременно пытаются изменить баланс одного счёта.

-- Транзакция 1: Перевод 100 у.е. со счёта 123 на счёт 456
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 123 FOR UPDATE; -- Эксклюзивная блокировка строки
-- Допустим, баланс = 500
UPDATE accounts SET balance = 400 WHERE id = 123;
UPDATE accounts SET balance = balance + 100 WHERE id = 456;
COMMIT;

Ключевой элемент — FOR UPDATE в SELECT. Эта конструкция устанавливает эксклюзивную блокировку на строку счёта 123. Если параллельно выполняется другая транзакция:

-- Транзакция 2: Попытка снять деньги со счёта 123
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 123 FOR UPDATE; -- Будет ждать разблокировки Транзакцией 1
-- Выполнится только после COMMIT Транзакции 1
UPDATE accounts SET balance = balance - 50 WHERE id = 123;
COMMIT;

Транзакция 2 будет приостановлена до завершения Транзакции 1, предотвращая одновременное изменение одного баланса.

В PHP с использованием PDO это выглядит так:

<?php
$pdo = new PDO('mysql:host=localhost;dbname=bank', 'user', 'pass');
$pdo->beginTransaction();

try {
    // Блокируем строку для обновления
    $stmt = $pdo->query("SELECT balance FROM accounts WHERE id = 123 FOR UPDATE");
    $balance = $stmt->fetchColumn();
    
    if ($balance >= 100) {
        $pdo->exec("UPDATE accounts SET balance = balance - 100 WHERE id = 123");
        $pdo->exec("UPDATE accounts SET balance = balance + 100 WHERE id = 456");
        $pdo->commit();
        echo "Перевод успешен!";
    } else {
        $pdo->rollBack();
        echo "Недостаточно средств!";
    }
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Ошибка: " . $e->getMessage();
}
?>

Проблемы и оптимизация блокировок

Блокировки могут привести к серьёзным проблемам производительности:

  • Взаимоблокировки (Deadlocks): Когда две или более транзакций взаимно блокируют друг друга. Например, Т1 блокирует строку A и запрашивает строку B, а Т2 блокирует B и запрашивает A. СУБД обычно обнаруживает deadlock и откатывает одну из транзакций.
  • Блокировки (Locks) и ожидания: Длительные транзакции могут удерживать блокировки, заставляя другие операции "простаивать".

Для минимизации рисков рекомендуется:

  • Сокращать время удержания блокировок (быстрее завершать транзакции).
  • Использовать наименьший необходимый уровень изоляции (например, READ COMMITTED вместо SERIALIZABLE).
  • В некоторых случаях применять оптимистичные блокировки (через версии записей или временные метки), где проверка конфликтов выполняется только при коммите.
-- Оптимистичная блокировка через версию
UPDATE accounts 
SET balance = 400, version = version + 1 
WHERE id = 123 AND version = 5; -- Если версия изменилась, обновление не пройдёт

Заключение

Блокировки — фундаментальный механизм обеспечения целостности данных в многопользовательских средах. Их корректное использование требует баланса между безопасностью операций и производительностью системы. В PHP-приложениях важно проектировать транзакции так, чтобы блокировки захватывались на минимально необходимое время, а также обрабатывать возможные исключения (например, deadlock) через повторные попытки или информирование пользователя.