Django Database Transactions

Source: Internet
Author: User
Tags exception handling savepoint

Managing Database Transactions

The Django Framework provides several ways to control and manage database transactions. (The following Django框架 will be simplified Django so that the reader can fill in 框架 two words by himself)

Default transactional behavior of the Django framework

Autocommit is the default transactional behavior of Django, which behaves as if the database operation is immediately committed to the database, unless the transaction is still active. So, see below for more details.

Django uses transactions or savepoint to guarantee the integrity of multiple ORM operations, especially for delete () and update () operations.

In addition, for some performance reasons, the TestCase class provided by Django wraps each test case in one transaction.

Binding a transaction to an HTTP request

In a Web application, a common way of dealing with transactions is to wrap each request in a single transaction. This feature is very simple to use, you only need to set its configuration item atomic_requests to True.

It works like this: When a request comes in, Django opens a transaction before invoking the View method. If the request is handled correctly and the result is returned correctly, Django commits the transaction. Otherwise, Django rolls back the transaction.

Similarly, you can use a savepoint in your view code to assume the role of a child transaction, a typical example being a atomic() context manager. Finally, all changes are either committed or rolled back.

警告!!!虽然这种事务模式的优势在于它的简单性,但在访问量增长到一定的时候会造成很大的性能损耗。这是因为为每一个视图开启一个事物会有一些额外的开销。另外,这种性能影响还取决于你的应用程序的查询模式以及你的数据库对锁的处理是否高效。
基于请求的事务和流式响应当一个视图返回一个StreamingHttpResponse时,读取响应的内容通常会执行一段代码去生成内容。但由于视图已经返回了结果,这些代码将运行在事务之外。一般而言,不建议在生成流式响应的时候写入数据库,因为目前还没有一个很好的方法来处理响应已经被发送之后的错误。

In practice, you can simply use atomic() adorners to decorate each view method to implement this function.

Note that it has a premise that your view code is running in a closed transaction. For example, the middleware can only run outside the transaction, so it is not difficult to understand why the rendering of the response template is not subject to transactional control.

Even if atomic_requests is turned on, you still have a way to make the view method run outside of the transaction.

non_atomic_requests (Using=none) [Source]

For example, you can have this decoration above to make the view method not subject to transaction control.

fromimport transaction@transaction.non_atomic_requestsdef my_view(request):    do_stuff()@transaction.non_atomic_requests(using=‘other‘)def my_other_view(request):    do_stuff_on_the_other_database()

Unfortunately, it can only bring mana to the magic that wears this coat.

Explicitly controlling transactions

Django also provides a separate API to control transactions.

Atomic (Using=none, savepoint=true) [Source]

Atomicity is a property of a database transaction. With Atomic, we can create an atomic block of code. Once the code block is complete, all modifications are committed to the database. Conversely, if there is an exception, the change is rolled back.

Blocks of code that are managed by Atomic can also be embedded into methods. In this case, even if the internal code block is working properly, if an external code block throws an exception, it will not be able to commit its modifications to the database.

Atomic can also be 装饰器 used as a, for example:

fromimport transaction@transaction.atomicdef viewfunc(request):    # This code executes inside a transaction.    do_stuff()

The following are used as context managers:

fromimport transactiondef viewfunc(request):    # This code executes in autocommit mode (Django‘s default).    do_stuff()    with transaction.atomic():        # This code executes inside a transaction.        do_more_stuff()

Once the atomic code block is placed in the try/except, the integrity error is naturally disposed of, such as the following example:

fromimport IntegrityError, transaction@transaction.atomicdef viewfunc(request):    create_parent()    try:        with transaction.atomic():            generate_relationships()    except IntegrityError:        handle_exception()    add_children()

In this example, even if the code in generate_relationships () breaks the data integrity constraints, you can still perform database operations in Add_children () and Create_ the changes produced by the parent () are also valid. It should be noted that the changes ingenerate_relationships () have been safely rolled back before calling Handle_exception () . Therefore, you can still manipulate the database in the exception handler if necessary.

尽量不要在atomic代码块中捕获异常因为当atomic块中的代码执行完的时候,Django会根据代码正常运行来执行相应的提交或者回滚操作。如果在atomic代码块里面捕捉并处理了异常,就有可能隐盖代码本身的错误,从而可能会有一些意料之外的不愉快事情发生。担心主要集中在DatabaseError和它的子类(如IntegrityError)。如果这种异常真的发生了,事务就会被破坏掉,而Django会在代码运行完后执行回滚操作。如果你试图在回滚前执行一些数据库操作,Django会抛出TransactionManagementError。通常你会在一个ORM相关的信号处理器抛出异常时遇到这个行为。捕获异常的正确方式正如上面atomic代码块所示。如果有必要,添加额外的atomic代码块来做这件事情。这么做的好处是:当异常发生时,它能明确地告诉你那些操作需要回滚,而那些是不需要的。

To ensure atomicity,atomic also banned some APIs. Actions such as attempting to commit, rolling back a transaction, and altering the autocommit state of a database connection are not allowed in the atomic code block, or an exception will be thrown.

Atomic uses a parameter to specify the name of the database. If the parameter does not have a value set, Django will use the system's default database.

The following is the Django transaction management code:

    • Open a transaction when entering the outermost atomic code block;
    • Create a savepoint when entering an internal atomic code block;
    • Releasing or rolling back a transaction when exiting an internal atomic;
    • Commits or rolls back a transaction when exiting the outermost atomic code block;

You can set the save point parameter to False to disallow internal code blocks from creating SavePoint. If an exception occurs, Django performs a rollback when exiting the first parent block and, if there is a savepoint, rolls back to the location of the savepoint, or rolls back to the outermost code block. The outer transaction can still guarantee atomicity. However, this option should be used only when the save point overhead is large. After all, it has a drawback: it destroys the error-handling mechanism described above.

You can also use atomicwhen the autocommit is closed. At this point, even the outermost code block, it uses only the savepoint.

性能考虑开启事务会消耗数据库服务器的性能。为了最大化减小这种开销,应该让事务尽可能的短。特别是当你把atomic()用在Django的请求/响应周期之外的一个耗时的操作中时,这点就显得尤为重要了。
Auto-commit why does Django use auto-commit by default?

The SQL standard indicates that each SQL query will open a new transaction unless an open transaction already exists. These transactions must subsequently be explicitly committed or rolled back.

This is not very convenient for application developers. To reduce this inconvenience, most databases provide autocommit mode. When Autocommit is turned on and there are no open transactions, each SQL query is wrapped up by its own transaction. In other words, not only does each query open a transaction, but the transaction also automatically commits or rolls back depending on whether the query succeeds.

The PEP (Python enhancement proposals) 249,python Database Specification v2.0 requires that autocommit be turned off at initialization time. Django has replicated it and turned on auto-commit.

To avoid this, you can turn off transaction management, but you are not recommended to do so.

Close Transaction Management

You can set autocommit to False in the configuration file to turn off transaction management for the specified database. If you close, Django will not perform automatic commits and will not perform any commits. In this way, you can get the general behavior of the underlying database.

This requires that you explicitly commit each transaction, whether it is a Django or a third-party library open transaction. So the most common scenario is that you want to use your own transactional middleware or do something strange.

Perform actions after commit

New features of Django1.9

Sometimes you want to perform some operations related to the current database transaction after the transaction has been successfully committed. For example, celery tasks, email notifications, or cache invalidation.

Django provides the On_commit () method to register some callback functions that execute only after the transaction has been successfully committed.

On_commit (func, Using=none) [source]

Pass any function that has no arguments to on_commit () .

fromimport transactiondef do_something():    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.transaction.on_commit(do_something)

You can also pass in anonymous functions.

transaction.on_commit(lambda: some_celery_task.delay(‘arg1‘))

??? When the assumed database write is successfully committed, the function you pass in will be executed immediately.

The function you pass in'll be called immediately after a hypothetical database write made where on_commit () is Called would be successfully committed.

When you use on_commit ()when there is no open transaction, the callback function will be executed immediately.

If the assumed database write operation becomes a rollback (typically an unhandled exception occurs in Atomic () , the function you pass in will be discarded and will never be executed.

Save Point

The savepoint (that is, the embedded Atomic () block) is always handled correctly. That is, the on_commit () callback function that is registered after a savepoint is executed after the external transaction is committed, except if there is a rollback between the hold point or any previous savepoint in the current transaction.

with transaction.atomic():  # Outer atomic, start a new transaction    transaction.on_commit(foo)    with transaction.atomic():  # Inner atomic block, create a savepoint        transaction.on_commit(bar)# foo() and then bar() will be called when leaving the outermost block

On the other hand, when a savepoint is rolled back (if an exception occurs), the internal callback function will not be called:

with transaction.atomic():  # Outer atomic, start a new transaction    transaction.on_commit(foo)    try:        with transaction.atomic():  # Inner atomic block, create a savepoint            transaction.on_commit(bar)            raise SomeError()  # Raising an exception - abort the savepoint    except SomeError:        pass# foo() will be called, but not bar()
Execution order

For a particular transaction, the On-commit function is executed in the order in which they were registered.

Exception handling

If a on-commit function throws an uncaught exception in a given transaction, then all registered functions in that transaction will not run. Of course, this is the same as the way you perform some methods manually in order.

Execution time

Your callback function executes after a commit has completed successfully, so failure to execute the callback function does not result in a rollback of the transaction. They are executed by the condition, but they are not part of the transaction. For some very purposeful use cases (email notifications, celery tasks, etc.) are good. If this is not the case (if your subsequent execution and the key, its failure means the failure of the transaction), then you will not use the on_commit () callback hook. Instead, you will be willing to use two-step commit such as PSYCOPG two-step commit protocol support, and the optional two-step commit extension mentioned in the Python db-api design documentation.

The callback function is not executed until autocommit is resumed in the post-commit link (because any query completed in the callback function will open an implicit transaction, blocking the link back to autocommit mode)

When using autocommit mode, and outside of a atomic () block, the function will run immediately, not after it is committed.

The On-commit function is only available when autocommit mode is turned on or in the Atomic ()(or atomic_requests) transaction API. An error will occur if you attempt to call On_commit ()when autocommit mode is off or outside of the atomic block.

Used in Tests

The TestCase class in Django wraps each test in a transaction and performs a rollback after the test is complete to provide isolation of the test. This means that nothing is actually committed, so your on_commit () callback function will never be executed. So, if you really want to use the on_commit () callback function, use the Transactiontestcase class instead of testcase.

There's nothing to roll back the hook function?

Because there are many factors that lead to implicit rollback, it is much harder to implement a simple, rude rollback hook than to commit a hook.

For example, if your database connection is disconnected because your process has been rudely killed, your rollback hook will never execute.

The solution is simple: instead of performing some action in the atomic block, and then undoing the operation after the operation fails, use the on_commit () delay to execute the first operation to the successful transaction. It's much easier than undoing some of the things you've never done in the first.

Underlying API
警告:尽可能的选择使用atomic()。它更契合每个数据的特性,并且阻止了非法操作。底层APIs仅仅在你实现了自己的事务管理时有用。

Original Link 1 |
Original Link 2

Django Database Transactions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.