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

Что такое пессимистичная блокировка?

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

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

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

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

Что такое пессимистичная блокировка?

Пессимистичная блокировка — это стратегия управления конкурентным доступом к ресурсам (например, данным в базе данных или объектам в памяти) в многопользовательских системах. Основная идея заключается в предположении, что конфликт при одновременном изменении данных вероятен, поэтому ресурс блокируется заранее на весь период его использования. Любой другой поток или процесс, пытающийся получить доступ к тому же ресурсу, будет заблокирован (ожидать или получить ошибку) до момента освобождения первой блокировки.

Этот подход противопоставляется оптимистичной блокировке, где конфликты считаются маловероятными, и проверка на конфликт происходит только при попытке фиксировать изменения.

Механизм работы в контексте баз данных

В системах, использующих пессимистичную блокировку (например, многие традиционные RDBMS), наиболее распространены два типа блокировок:

  • Блокировка для чтения (SELECT ... FOR SHARE или LOCK IN SHARE MODE) — позволяет другим транзакциям читать данные, но запрещает их изменение.
  • Блокировка для записи (SELECT ... FOR UPDATE) — наиболее строгий тип. Она запрещает другим транзакциям как читать (в некоторых реализациях), так и изменять заблокированные строки.

Пример на языке SQL:

-- Транзакция 1 начинает работу и блокирует строку для обновления
BEGIN TRANSACTION;
SELECT * FROM accounts WHERE id = 123 FOR UPDATE;
-- В этот момент строка с id=123 заблокирована для других транзакций.
-- Транзакция 1 может выполнять вычисления или другие операции.

-- Транзакция 2 пытается получить доступ к той же строке
BEGIN TRANSACTION;
SELECT * FROM accounts WHERE id = 123 FOR UPDATE;
-- Эта команда будет ОЖИДАТЬ, пока Транзакция 1 не завершится (COMMIT или ROLLBACK).
-- Или, если настроено время ожидания, завершится с ошибкой.

-- Транзакция 1 завершает работу
UPDATE accounts SET balance = balance - 100 WHERE id = 123;
COMMIT;

-- После COMMIT Транзакции 1 блокировка освобождается, и Транзакция 2 может продолжить выполнение.

Реализация пессимистичной блокировки в Go

В Go пессимистичная блокировка часто реализуется на уровне приложения для защиты общих структур в памяти с помощью мьютексов из стандартной библиотеки sync. Мьютекс — это классический пример пессимистичного подхода: он предполагает, что конфликт возможен, и поэтому захватывает исключительный доступ к ресурсу.

package main

import (
    "sync"
    "time"
)

type SharedCounter struct {
    mu    sync.Mutex // Пессимистичная блокировка - мьютекс
    value int
}

func (sc *SharedCounter) Increment() {
    sc.mu.Lock()         // ЗАХВАТ блокировки перед изменением данных.
    // В этот момент любой другой вызов Increment() будет ждать.
    sc.value++
    sc.mu.Unlock()       // ОСВОБОЖДЕНИЕ блокировки.
}

func main() {
    counter := &SharedCounter{}
    
    // Запускаем несколько горутин, которые конкурируют за доступ к counter.
    for i := 0; i < 5; i++ {
        go func() {
            for j := housekeeping; j < 5; j++ {
                counter.Increment()
                time.Sleep(10 * time.Millisecond)
            }
        }()
    }
    
    time.Sleep(1 * time.Second)
    // Благодаря мьютексу значение counter будет точно 25, несмотря на конкурентный доступ.
}

Когда использовать пессимистичную блокировку?

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

Основные недостатки

  • Снижение производительности и масштабируемости: Блокировки создают ожидание, уменьшая параллельную работу системы. При высокой нагрузке это может привести к "очередям" из ожидающих процессов.
  • Риск взаимных блокировок (deadlock): Если два или более процессов блокируют разные ресурсы и затем пытаются захватить ресурсы друг друга, система может заблокироваться полностью. Это требует дополнительного анализа и профилактики.
  • Увеличение времени ответа: Клиенты или пользователи могут ощущать замедление, если их запросы часто ожидают освобождения блокировок.

В итоге, пессимистичная блокировка — это надежный и понятный механизм для предотвращения race condition и обеспечения строгой консистентности данных. Однако ее применение должно быть взвешенным, особенно в высоконагруженных распределенных системах, где цена блокировки может быть слишком высокой. В Go для защиты внутренних структур данных мьютексы являются стандартным и эффективным инструментом реализации этого подхода.