Atomic Increment in Rails

Many times you are put in a situation that you need to increment an ActiveRecord attribute, but you need to make it Atomic to avoid any concurrency problems.
Using the ActiveRecord#increment! is not the answer.

  post.increment! :posts_count

the previous code results the following SQL:

  UPDATE 'posts' SET 'posts_count' = 1 WHERE 'id' = 38

This for sure is not Atomic since there is a read operation for the attribute then incrementing it with ruby then update that field with the new value.
The right answer is “increment_counter” . it is a class method that makes a real atomic update .

  Post.increment_counter :posts_count , 38

take alook at the result SQL:

  UPDATE 'posts' SET 'posts_count' = COALESCE('posts_count', 0) + 1 WHERE ( 'id'= 38)

Clearly it is Atomic and no threat of a concurrency(并发) problem.

A side note COALESCE() function is used to return the first not-Null value from the passed array. it is used here to handle the case that this atribute is Null as a Zero.

If you need to increment multiple attributes or even increment an attribute with a value other than 1. A very helpful class method is "update_counters"

  Post.update_counters 38 , :posts_count => 2 , :update_calls_count => 1

The result SQL is

  UPDATE 'posts' SET 'posts_count' = COALESCE('posts_count', 0) + 2, 'update_calls_count' = COALESCE('update_calls_count', 0) + 1 WHERE ('id' = 38)
Posted in Uncategorized