Ответ
Оптимистичная блокировка предполагает, что конфликты при одновременном изменении данных маловероятны. Она проверяет, не изменились ли данные с момента их чтения, только в момент фиксации транзакции (commit). Если данные были изменены другой транзакцией, выбрасывается исключение (например, OptimisticLockException). Реализуется через поля версии (@Version) или метки времени (timestamp).
Пессимистичная блокировка предполагает частые конфликты и предотвращает их, блокируя строку или таблицу на уровне базы данных сразу при чтении для изменения. Это гарантирует эксклюзивный доступ, но снижает параллелизм.
Ключевые различия:
- Подход: Оптимистичная — «проверить и обновить», пессимистичная — «заблокировать, затем изменить».
- Блокировка в БД: Оптимистичная не устанавливает блокировок при чтении, пессимистичная — устанавливает (например,
SELECT ... FOR UPDATE). - Производительность: Оптимистичная обычно обеспечивает лучшую производительность при низкой конкуренции. Пессимистичная может приводить к ожиданиям и deadlock'ам.
- Использование: Оптимистичная подходит для сценариев с редкими конфликтами (веб-приложения). Пессимистичная — для критичных данных с высокой конкуренцией (финансовые операции).
Пример оптимистичной блокировки (JPA/Hibernate):
@Entity
public class Account {
@Id
private Long id;
private BigDecimal balance;
@Version
private Long version; // Автоматически увеличивается при каждом обновлении
}
// При коммите, если version в БД отличается от version в объекте, будет выброшено OptimisticLockException
Пример пессимистичной блокировки (JPA):
// Блокировка строки для эксклюзивного изменения
Account account = entityManager.find(Account.class, accountId, LockModeType.PESSIMISTIC_WRITE);
// Или с использованием запроса
Query query = entityManager.createQuery("SELECT a FROM Account a WHERE a.id = :id");
query.setParameter("id", accountId);
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
Account account = (Account) query.getSingleResult();