ГоловнаВсі публікаціїКатегоріїПро проєкт

Pessimistic Lock у Rails: що це таке і коли застосовувати. Які є альтернативи?

Обкладинка нотатки: Pessimistic Lock у Rails: що це таке і коли застосовувати. Які є альтернативи?
Зміст дописунатисність на посилання, щоб перейти до потрібного місця
Якщо ви працюєте з Rails і вам потрібно уникнути одночасної зміни одного запису декількома процесами, варто звернути увагу на механізм блокування записів у базі даних. Один із найнадійніших способів зробити це — pessimistic locking.

Що таке pessimistic lock?

Pessimistic lock (песимістичне блокування) означає, що запис у базі даних фізично блокується для змін з інших потоків або процесів, поки поточна операція не завершиться. Тобто якщо один процес отримав блокування на запис, інші мусять чекати, поки він його звільнить.
У ActiveRecord песимістичне блокування реалізується через метод lock, який додає SELECT ... FOR UPDATE, що утримує блокування до кінця транзакції.

Використання в Rails

Ось простий приклад використання lock у Rails:
ActiveRecord::Base.transaction do
  order = Order.lock.find(order_id)
  order.status = "processed"
  order.save!
end
У цьому випадку, якщо інший процес спробує отримати Order із тим самим order_id, він змушений буде чекати, поки поточний процес завершить транзакцію.

Навіщо це потрібно?

Уявімо, що ми обробляємо замовлення. Коли користувач натискає кнопку "Оплатити", нам потрібно зменшити кількість товару на складі. Якщо кілька людей одночасно намагаються купити останню одиницю товару, без блокування можливий race condition:
  1. Процес 1 читає кількість товару (1 одиниця).
  2. Процес 2 читає ту ж саму кількість (1 одиниця).
  3. Обидва процеси намагаються записати нове значення (0 одиниць).
  4. Один з процесів втрачає оновлення іншого.
Якщо ж використати lock, другий процес буде змушений дочекатися завершення першого і вже потім вирішувати, що робити.

Альтернативи pessimistic lock

Pessimistic locking не завжди найкращий вибір, оскільки він може блокувати інші процеси, уповільнюючи роботу застосунку. Іноді краще використовувати:
  1. Optimistic Locking — перевіряє, чи змінився запис між читанням і записом.
  2. Atomic операції — використовує UPDATE ... WHERE або increment! без читання значень у Ruby.
  3. Queue-based підхід — розподіляє оновлення через чергу (Sidekiq, RabbitMQ).

Optimistic Locking у Rails

Optimistic locking працює через колонку lock_version. Якщо два процеси читають запис, то при спробі записати зміни система перевіряє, чи не змінився запис за цей час:
class Order < ApplicationRecord
  attr_accessor :lock_version
end
Тоді, якщо один процес внесе зміни, а інший спробує записати застарілу версію, він отримає ActiveRecord::StaleObjectError.
Якщо простими словами:
  • Pessimistic locking блокує запис, щоб уникнути конфліктів.
  • Optimistic locking дозволяє працювати без блокування, але потребує обробки конфліктів.
  • Atomic операції зменшують ризик race condition без блокувань.
Обирайте правильний підхід залежно від задачі. Якщо критично уникнути конфліктів за будь-яку ціну — використовуйте lock. Якщо важлива продуктивність і можна дозволити конфлікти — краще lock_version або atomic updates.
Структура Promise (JavaScript) та як з цим працювати
18.02.2025 14:33

Структура Promise (JavaScript) та як з цим працювати

meme code
meme code@memecode
Що таке Memoization (приклади Ruby та Ruby on Rails)?
20.02.2025 18:16

Що таке Memoization (приклади Ruby та Ruby on Rails)?

meme code
meme code@memecode
Що таке debounce у JavaScript і чому це важливо?
21.03.2025 16:39

Що таке debounce у JavaScript і чому це важливо?

meme code
meme code@memecode
Що таке CFB (Cipher Feedback)?
21.03.2025 16:53

Що таке CFB (Cipher Feedback)?

meme code
meme code@memecode
Що таке XOR і як він працює?
21.03.2025 17:05

Що таке XOR і як він працює?

meme code
meme code@memecode
Embed програмування: що це таке і з чого почати
24.03.2025 16:48

Embed програмування: що це таке і з чого почати

meme code
meme code@memecode
Чому PostgreSQL пропускає ID при збережені нових записів? (Heroku)
31.03.2025 19:13

Чому PostgreSQL пропускає ID при збережені нових записів? (Heroku)

meme code
meme code@memecode