Solve the pit that Django transaction stepped on in transaction management

  • 2021-11-01 04:04:53
  • OfStack

Summary

Transaction is the implementation of django for database atomicity operation at python level.

Simply put, the code block wrapped by transaction. atomic () only performs commit at the database level after the code block is successfully completed. In the actual development, I encountered some problems.

1. commit operations for the database are not performed within an transaction transaction

Unless manual commit

The most basic functions of transaction.

Code scenario:

The celery asynchronous task is started at the current transaction, and uncommitted changes cannot be obtained.


def example_view(request):
    with transaction.atomic():
        change_obj() #  Modify object variables 
        obj.save()
        async_task.delay(obj.id)
def async_task(obj_id):
    obj = Model.objects.get(pk=obj_id)
    read_the_obj() #  Read object information 

In using transaction, Model. save () does not do commit, so if asynchronous tasks are set in transaction and get () is used to query the database, no object changes in transactions will be seen. This is also the transaction isolation level to realize "repeatable reading", that is, multiple queries in the same transaction should keep the results unchanged.

2. transaction manages transactions only for database layer operations

Transaction management that cannot be understood as python operation

The code is as follows:


def example_view(request):
    tag = False
    with transaction.atomic():
        tag = True
        change_obj() #  Modify object variables 
        obj.save()
        raise DataError
    print("tag = ",tag)

tag = True # Output content 

Even if DataError occurs in the transaction code block, the transaction rollback is only a database-level rollback, and the operation against python is still completed.

Even operations on Model. Object will exist in variables.

Such as:


def example_view(request):
    obj.changed = False
    with transaction.atomic():
        obj.changed = True
        change_obj() #  Modify other variables of the object 
        obj.save()
        raise DataError
    print("obj.changed = ",obj.changed)

obj.changed = True # Output content 

A rollback with an Dataerror exception only operates at the database level, so it is not possible to judge whether the transaction completed correctly based on the attribute value of model object.

In addition, although Django abstracts the database level with ORM, it should be clearly realized that the model object we operate is essentially different from the database content, and DJANGO only performs database operations during query and submission.

Supplement: How to use Django transaction transaction. atomic ()

Look at the code ~


from django.shortcuts import render
from django.http import HttpResponse
from django.views.generic import View
from django.db import transaction   #  Import transaction  
 
#  Class view  ( Affairs ,@transaction.atomic Decorator )
class MyView(View): 
    @transaction.atomic
    # transaction.atomic The decorator ensures that all database operations in this function are in the 1 In a transaction. 
    def post(self, request):
 
        #  Database operation 1 . . . 
        #  Database operation 2 . . .         
        return HttpResponse('ok') 
 
#  Class view  ( Affairs , Use of Savepoint )
class MyView2(View):
    @transaction.atomic
    def post(self, request): 
        #  Setting Transaction Savepoint 
        s1 = transaction.savepoint()   #  You can set multiple save points 
 
        #  Database operations. . . 
 
        #  Transaction rollback  ( If an exception occurs , Roll back the transaction )
        transaction.savepoint_rollback(s1)  #  You can roll back to the specified save point 
 
        #  Commit transaction  ( If there is no exception , Commit a transaction )
        transaction.savepoint_commit(s1)
 
        #  Return a reply 
        return HttpResponse('ok')    

Related articles: