Что такое пессимистическая блокировка (pessimistic locking) в контексте транзакций?

Ответ

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

Принцип работы:

  1. Транзакция A, желая изменить строку, явно запрашивает блокировку (например, SELECT ... FOR UPDATE в SQL).
  2. База данных немедленно блокирует эту строку для транзакции A.
  3. Если транзакция B попытается получить такую же блокировку на те же данные, она будет приостановлена (ждет) или получит ошибку, пока транзакция A не завершится (commit или rollback).

Реализация в JPA (Java Persistence API):

@Entity
public class Account { 
    @Id 
    private Long id;
    private BigDecimal balance;
    // ...
}

// В сервисном слое
@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
    // Пессимистическая блокировка записи на запись
    Account fromAccount = entityManager.find(
        Account.class, 
        fromId, 
        LockModeType.PESSIMISTIC_WRITE
    );
    // Блокировка гарантирует, что баланс не изменится другой транзакцией до commit.
    if (fromAccount.getBalance().compareTo(amount) >= 0) {
        fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
        // ... логика для получателя
    }
}
Плюсы и минусы: Плюсы Минусы
Гарантирует целостность данных, предотвращая конфликты «потерянного обновления». Снижает производительность и масштабируемость из-за ожиданий.
Проще для понимания (явная блокировка). Высокий риск взаимных блокировок (deadlock).
Подходит для операций с долгими транзакциями или высокой конкуренцией за данные. Неэффективно, если конфликты редки.

Альтернатива: Оптимистическая блокировка (optimistic locking), которая использует версионирование и проверяет конфликт только при коммите.

Ответ 18+ 🔞

Так, слушай, про блокировки. Есть же два лагеря: одни как будто в розовых очках — «ой, авось пронесёт, никто не тронет мои данные», а другие — законченные параноики. Вот пессимистическая блокировка — это как раз про вторых, про мудаков, которые сразу кричат «моё!» и никому не дают прикоснуться, пока сами не наиграются.

Как это работает, если на пальцах:

  1. Транзакция А, такая вся серьёзная, подходит к строке в базе и говорит: «Эту штуку я сейчас буду менять, и чтобы никто, блядь, даже близко не подходил». Делает SELECT ... FOR UPDATE — это как красная лампочка загорается.
  2. База данных тут же, как верный овчарка, хватает эту строку за горло и отдаёт под контроль транзакции А.
  3. Если тут же прибежит транзакция Б, такая же резвая, и попробует сделать то же самое — её просто поставят нахуй в очередь. Будет стоять, тупить, ждать, пока А всё не сделает и не отпустит замок. Либо сразу получит по ебалу с ошибкой — зависит от настроения.

Как это выглядит в коде, на JPA: Смотри, вот у нас сущность Account, с балансом, всё как у людей.

@Entity
public class Account { 
    @Id 
    private Long id;
    private BigDecimal balance;
    // ...
}

// А вот в сервисе, где деньги переводят
@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
    // ВОТ ОНА, МАГИЯ ПАРАНОИКА. Не просто найти, а найти и тут же впендюрить пессимистическую блокировку на запись.
    Account fromAccount = entityManager.find(
        Account.class, 
        fromId, 
        LockModeType.PESSIMISTIC_WRITE
    );
    // Всё, теперь этот баланс — наш личный заложник. Ни одна другая транзакция его тронуть не посмеет.
    if (fromAccount.getBalance().compareTo(amount) >= 0) {
        fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
        // ... ну и там дальше логика, для получателя
    }
}

Ну и что мы имеем в сухом остатке, а?

Что хорошего (типа) Что полное говно
Данные под бронежилетом. Никаких «ой, а я тоже только что это поменял, прости». Производительность летит в пизду. Все стоят и ждут, как лохи.
Модель простая, для дебилов: взял замок — царь горы. Взаимные блокировки (deadlock) — это твой новый кошмар. Два чувака схватили друг другу ресурсы и ждут, пока первый отпустит. Ёперный театр!
Идеально, если у вас там драка насмерть за одну строчку в базе, или транзакции на полчаса. Если конфликты раз в год, то ты просто, блядь, зря всех тормозишь. Идиот.

Короче, если ты не уверен в людях (а в своих коллег по проекту ты никогда не уверен), и знаешь, что драка будет жёсткая — можешь так делать. Но помни, за надёжность платят скоростью. А альтернатива — оптимистическая блокировка — это когда ты сначала всё делаешь, а потом при коммите смотришь: «А не ебнул ли кто-нибудь мои исходные данные пока я тут вычислял?». Если ебнул — получаешь по щам и начинаешь заново. Но зато все летают свободно, пока не столкнутся.