Ответ
Оптимистическая и пессимистическая блокировки — это две стратегии управления одновременным доступом к данным (concurrency control) для предотвращения конфликтов.
Оптимистическая блокировка (Optimistic Locking)
Идея: Конфликты происходят редко. Система не блокирует данные при чтении, а «надеется» на лучшее. Блокировка происходит только в момент записи, причем система проверяет, не изменились ли данные с момента их чтения.
Как работает:
- Клиент читает данные вместе с их версией (числом или timestamp).
- Клиент выполняет необходимые изменения в приложении.
- При попытке записать изменения клиент отправляет новые данные и версию, которую он прочитал.
- Система обновляет запись только если текущая версия в базе данных совпадает с той, что прислал клиент. После успешного обновления версия увеличивается.
- Если версии не совпадают, значит, другой клиент уже успел изменить данные. Транзакция откатывается, и клиенту возвращается ошибка.
Пример в Go (псевдокод):
// 1. Читаем запись и ее версию
var version int
err := db.QueryRow("SELECT name, version FROM products WHERE id = 1").Scan(&name, &version)
// 2. Пытаемся обновить, проверяя версию в WHERE
result, err := db.Exec(
"UPDATE products SET name = $1, version = version + 1 WHERE id = $2 AND version = $3",
"New Name", 1, version,
)
// 3. Проверяем, была ли строка обновлена
rowsAffected, _ := result.RowsAffected()
if rowsAffected == 0 {
return errors.New("конфликт обновления: данные были изменены другим пользователем")
}
- Плюсы: Высокая производительность при низкой интенсивности конфликтов, так как нет долгих блокировок.
- Минусы: При высокой интенсивности конфликтов много транзакций будут откатываться, что снижает эффективность.
Пессимистическая блокировка (Pessimistic Locking)
Идея: Конфликты вероятны. Система блокирует данные сразу при чтении, чтобы никто другой не мог их изменить до завершения транзакции.
Как работает:
- Клиент начинает транзакцию и запрашивает данные с явной блокировкой (например,
SELECT ... FOR UPDATE). - База данных блокирует выбранные строки. Другие транзакции, пытающиеся получить доступ к этим строкам, будут ждать снятия блокировки.
- Клиент выполняет изменения и завершает транзакцию (commit или rollback).
- Блокировка снимается.
- Плюсы: Гарантирует, что транзакция завершится успешно, если она получила блокировку. Идеально для сред с высокой вероятностью конфликтов.
- Минусы: Снижает параллельность работы системы. Может приводить к
deadlock-ам (взаимным блокировкам).
Ответ 18+ 🔞
А, слушай, про эти ваши блокировки, оптимистические и пессимистические. Ну, это как два подхода к жизни, блядь. Один — как наивный студент, а другой — как параноик с топором у кассы.
Оптимистическая блокировка (Optimistic Locking)
Вот представь, идешь ты в магазин за последней бутылкой водки. Оптимист такой думает: «Да кому она нахуй нужна, кроме меня? Конфликтов же не будет!» Берёшь её с полки, смотришь на ценник — это типа версия товара, блядь. Идёшь к кассе, а там уже очередь. Пока стоишь, представляешь, как её будешь распивать. Подходишь, а кассирша такая: «Ой, а эту только что последний мужик просканировал, извините». И всё, пиздец твоей мечте. Транзакция откатилась, иди нахуй.
Как оно на самом деле работает:
- Считал ты данные и их версию (как тот ценник).
- Поменял что-то у себя в голове (или в приложении).
- Прибежал записывать, сука, а там говорят: «А пока ты тут думал, версию уже сменили!».
- Обновят твои данные только если версия совпала. Не совпала — получай ошибку и иди перечитывай всё заново, лох.
Вот, смотри, как это в коде выглядит, ёпта:
// 1. Читаем запись и ее версию
var version int
err := db.QueryRow("SELECT name, version FROM products WHERE id = 1").Scan(&name, &version)
// 2. Пытаемся обновить, проверяя версию в WHERE
result, err := db.Exec(
"UPDATE products SET name = $1, version = version + 1 WHERE id = $2 AND version = $3",
"New Name", 1, version,
)
// 3. Проверяем, была ли строка обновлена
rowsAffected, _ := result.RowsAffected()
if rowsAffected == 0 {
return errors.New("конфликт обновления: данные были изменены другим пользователем")
}
- Плюсы: Быстро, если все друг другу не мешают. Как на широкой дороге — все едут и не дерутся.
- Минусы: А если на той же бутылке водки очередь? Все будут её хватать, а потом откатываться с ошибкой. Сплошные конфликты, эффективность — ноль ебать.
Пессимистическая блокировка (Pessimistic Locking)
А это уже подход моего деда, который в советское время за дефицитом гонялся. Подошёл к прилавку, схватил банку тушёнки и держит, сука, как маньяк. «Моё! Никому не отдам!». И стоит так, пока не расплатится. Все остальные вокруг ходят, злые, но нихуя не могут сделать — он же первый схватил и не отпускает.
Как это в системе:
- Начинаешь транзакцию и сразу говоришь: «Дай мне эти данные И ЗАБЛОКИРУЙ ИХ, БЛЯДЬ, НИКОМУ БОЛЬШЕ!» (
SELECT ... FOR UPDATE). - База данных берёт и навешивает замок на эти строки. Все, кто после пришли, — ждут, как лохи.
- Ты неспеша делаешь свои дела, меняешь данные.
- Закончил — закрыл транзакцию, отпустил блокировку. Только тогда следующий в очереди может попробовать схватить.
- Плюсы: Гарантия, что если уж ты вцепился — то доведёшь дело до конца. Для ситуаций, где все друг другу готовы морду набить за ресурс.
- Минусы: Параллельность работы летит в пизду. Все стоят и ждут. А если два таких параноика схватятся друг за друга (один заблокировал A и хочет B, а второй заблокировал B и хочет A) — вот вам и deadlock, ёперный театр! Сидят и смотрят друг на друга, как дураки.
Итог, блядь:
Если у тебя народ культурный и редко друг другу мешает — бери оптимистическую, будет быстро.
А если у тебя там, блядь, дикий запад, все лезут одновременно в одну запись — ставь пессимистическую, и пусть ждут своей очереди, пидарасы.
Вот и вся философия, в рот меня чих-пых.