Locking ActiveRecord Of Rails

Situation

Data consistency is very important in many applications, especially for financial and banking applications, etc. A small error can become a tragedy if we don't take it seriously. This time, I'll talk a bit about Locking and how you can use it effectively.

Why Is Locking So Necessary?

Imagine you are building an application in which each person will have an account with with a virtual money. And the user whose id is 5 is accessing the site to buy some items, we get into this account like this:

account = Account .find_by_user_id ( 5 )

After choosing your favorite item for $ 50, click check and start paying for the item. Before making a request, we will first check if he has enough money in his account, and if he satisfies the conditions, we will then reduce his account balance. an amount corresponding to the price of the item.

That seems easy, isn't it? However, if what this guy will open is a tab of the site, select another item for $ 80 and somehow click on both tabs. Although it is very rare, there may be a chance when requests on the first and second tabs to the server almost at the same time, and they are all handled by the server simultaneously. This is how the request on the first tab has been done:

But after executing account.balance = account.balance – item.price and before saving to account, the CPU performs the second request (with the same code):

I'm sure you can see the problem now. Although after purchasing the first item, we will think that the user only has $ 50 in his account, and in theory he cannot buy another item for more than $ 50. But here, he can buy both items because it passes the condition tests.

By using Locking, we can prevent the same situation. When Locking is in place, they will not allow two processes to update objects at the same time.

In general, there are two types of Locking: Optimistic and Pessimistic . Slowly, I think you can also partly guess their true meaning.

Optimistic Locking

In this type, many users can access the same object to read its value, but if two users perform an update, there will be conflicts, only one user will succeed and one will others will not be done.

To create Optimistic locking , you can create a lock_version field that you want to set the lock and Rails will automatically check before updating the object. Its mechanism is quite simple. Each time the object is updated, lock_version value will be increased. Therefore, if two requests want to execute the same object, the first request will succeed because its lock_version is the same as when it is read. But the second request will fail because lock_version has been increased in the database of the first request.

In this kind of locking, you are responsible for handling the exceptions returned when updating the failed action. You can read more here:

http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html

Pessimistic Locking

With this kind of locking, only the first user to access the object will be able to update it. All other users will be excluded from even reading objects (remember that in Optimistic locking , we only lock it when updating data and users can still read it).

Rails will implement Pessimistic Locking by issuing special queries in the database. For example, suppose you want to retrieve the account object and lock it until you complete the update:

You can refer to more:

http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

Conclude

Locking should be used depending on the requirement. Without any special requirements, Optimistic locking is enough because it is more flexible and more concurrent requests can be served. In the case of Pessimistic Locking, you need to make sure you unlock when you finish updating the object.

Happy coding!

ITZone via kipalog

Libra writer

Share the news now