Cả hai đều ngăn race condition khi nhiều user sửa cùng record.
Optimistic Locking (default khi có cột lock_version):
- Không lock DB. Rails gắn lock_version vào record. Khi save, kiểm tra version có khớp không — nếu user khác đã sửa trước → raise ActiveRecord::StaleObjectError.
- Tốt cho trường hợp conflict ít xảy ra.
# Migration: add_column :products, :lock_version, :integer, default: 0
product = Product.find(1) # lock_version = 5
# ... user khác cũng đang sửa ...
product.update!(name: "New") # raise StaleObjectError nếu version đổiPessimistic Locking (DB-level lock):
- Dùng SQL SELECT ... FOR UPDATE — record bị lock cho đến khi transaction kết thúc.
Product.transaction do
product = Product.lock.find(1) # SELECT ... FOR UPDATE
product.decrement!(:stock)
endDùng Pessimistic khi conflict xảy ra thường xuyên (e.g. trừ kho).
Optimistic khi conflict hiếm.
Both prevent race conditions when multiple users edit the same record simultaneously.
Optimistic Locking (enabled by a lock_version column):
- No DB lock. Rails tracks a lock_version. On save, it checks if the version still matches — if another user saved first → raises ActiveRecord::StaleObjectError.
- Good when conflicts are rare.
# Migration: add_column :products, :lock_version, :integer, default: 0
product = Product.find(1) # lock_version = 5
# ... another user edits concurrently ...
product.update!(name: "New") # raises StaleObjectError if version changedPessimistic Locking (DB-level lock):
- Uses SQL SELECT ... FOR UPDATE — the row is locked until the transaction ends.
Product.transaction do
product = Product.lock.find(1) # SELECT ... FOR UPDATE
product.decrement!(:stock)
endUse Pessimistic when conflicts are frequent (e.g. inventory deduction).
Use Optimistic when conflicts are rare.