All original content is created in Ukrainian. Not all content has been translated yet. Some posts may only be available in Ukrainian.Learn more

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

Post cover: Pessimistic Lock у Rails: що це таке і коли застосовувати. Які є альтернативи?
This content has not been translated yet.We're showing the original Ukrainian content below.
Якщо ви працюєте з 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.

This post doesn't have any additions from the author yet.

Структура Promise (JavaScript) та як з цим працювати
18 Feb 14:33

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

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

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

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

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

meme code
meme code@memecode
What is CFB (Cipher Feedback)?
21 Mar 16:53

What is CFB (Cipher Feedback)?

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

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

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

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

meme code
meme code@memecode
Why does PostgreSQL skip ID when saving new records? (Heroku)
31 Mar 19:13

Why does PostgreSQL skip ID when saving new records? (Heroku)

meme code
meme code@memecode
[Codecov] What is the difference between patch and project coverage?
09 Apr 16:03

[Codecov] What is the difference between patch and project coverage?

meme code
meme code@memecode
How do Scratch courses help children develop soft skills?
11 Apr 18:24

How do Scratch courses help children develop soft skills?

meme code
meme code@memecode
24 Apr 20:17

Фіксимо minikube "You are trying to run the amd64 binary on an M1 system."

meme code
meme code@memecode
24 Apr 20:55

Фіксимо minikube на Mac з М1 (відмовляємось від qemu, запускаємо на docker)

meme code
meme code@memecode
Where can I find the older version of Google Chrome and download it? On the example of an old Mac
25 Apr 23:02

Where can I find the older version of Google Chrome and download it? On the example of an old Mac

meme code
meme code@memecode