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.
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)