I'm using MySQL with the InnoDB engine and REPEATABLE-READ isolation level.
I have written a function which I think should atomically increment an IntegerField, and give me the value after the increment. I would like opinions on whether my code is robust against concurrency issues.
My code looks like this:
class MyModel(models.Model):
version = models.IntegerField()
@staticmethod
@transaction.commit_on_success
def acquire_version(pk):
MyModel.objects.filter(pk = pk).update(version = F('version') + 1)
return MyModel.objects.get(pk = pk).version
My thinking is that in two concurrent calls, the UPDATEs will mutually exclude one another because of a write lock, and then REPEATABLE-READ should guarantee that my subsequent .get will give me the value after the UPDATE. Am I right?
(This is not a general "how do I do an atomic increment?" question, there's already one of those. This is about whether this one particular way is valid.)
A general rule-of-thumb is that any sort of custom queries or customized query behavior should go into manager methods. This makes sense in your case, because you can increment, save and return the version number at a very low level: during the actual query.
Thus, use a manager (object = MyManager()
) and write a SQL query that increments the version number (UPDATE mytable SET version=(version+1) WHERE pk=pk
, see here), and immediately return the incremented version of the model instance, before any other call can be executed.
See also Managers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With