ActiveRecord Optimistic Locking

I briefly covered distributed locks and pessimistic locking here. In this specific post, I’ll cover optimistic locking.

Optimistic locking is just an alternative to pessimistic locking except that it sort of “builds in” locking mechanisms to an entire table and its corresponding ActiveRecord model. In pessimistic locking, you have to manually call with_lock on an ActiveRecord model while in optimistic locking, you introduce a column called lock_version in your database table, which automatically enables optimistic locking.

The lock_version column will be incremented every time a change is committed to the record in question. Thus, if there are two processes accessing the same record, and one process makes an update to the record, the second process won’t be able to modify the record unless it re-retrieves the newly updated data. This can prevent problems that can come with concurrent access to the same data.

This is pretty much straight from the Rails docs but I can’t think of any better way to explain some example usages of optimistic locking, so here goes.

Example 1: Optimistic locking preventing two instances of the same record overriding each other.

Example 2: Optimistic locking preventing deletion of the same record when lock_version is out of date.

To add optimistic locking to an ActiveRecord model, add the column lock_version to your database table with a datatype of integer. Something like this.

lock_version is the default column name that Rails will look for, but you can also customize the column name by overriding an attribute called locking_column within the ActiveRecord model like this.

Personally, I prefer pessimistic locking since I can choose specific instances where I want to lock records. To me, optimistic locking seems akin to the evil (in my mind) default_scope that override default scoping behaviors in ActiveRecord.

I would say optimistic locking is a toolbox that one can grab for, but only do so when there’s a really good reason to do it as it completely overrides out-of-box default ActiveRecord behavior.