Django 事务详解

Django 1.4 事务默认模式是autocommit模式,每个查询都相当于一个事务,每次查询都直接提交commit事务,
除非事务被禁止

Django’s default behavior is to run in autocommit mode. Each query is immediately committed to the database, unless a transaction is active.

Transaction

  • @transaction.autocommit() 使用django默认事务模式,就是每个查询都相当于一个事务,提交后自动commit
  • @transactioncommit_on_success() ((django 1.8: transaction.atomic() ) 自己控制view或者其他需要事务的代码
  • @transaction.commit_manually() 自己控制commit和rollback,所以代码里面必须显式调用commit 或者 rollback,哪怕只有读的查询

在view里面的使用:

  1. 装饰器
@transaction.commit_on_success
def view():
    a.save()
    b.save()
    return ...
  1. with用法
def func()
    with transaction.commit_on_success():
        a.save()
        b.save()
    return ...

执行查看mysql 的genernal_log

        # django 根据db读写路由,使读和写各生成了一个connect 链接数据库

        # 32455 这个是负责查询
        32455 Connect   [email protected] on owan
        32455 Query SET NAMES utf8mb4
        32455 Query set autocommit=0
        32455 Query SET SQL_AUTO_IS_NULL = 0
        32455 Query SELECT ... from a WHERE `id` = 20

        # 32456 这个是负责更新
        32456 Connect   [email protected] on owan
        32456 Query SET NAMES utf8mb4
        32456 Query set autocommit=0
        32456 Query SET SQL_AUTO_IS_NULL = 0
        32456 Query SELECT (1) AS `a` FROM `user_community_signin` WHERE `user_community_signin`.`id` = 20  LIMIT 1
        32456 Query UPDATE a SET `user_id` = ....

        # 32455 这个是负责查询 ,第二个查询,依然使用32455这个链接
        32455 Query SELECT ...from b where .`id` = 1

        # 32456 依然使用这个32456链接来更新数据
        32456 Query SELECT (1) AS `a` FROM `community_point` WHERE `community_point`.`id` = 1  LIMIT 1
        32456 Query UPDATE b set `id` = ...

        # 32456  更新操作commit
        32456 Query commit    
        # (rollback 如果两个更新有任何出错)
        # 32455 Query   rollback    
        # 32456 Query   rollback   
        32455 Quit  
        32456 Quit

如果没有加 transaction.commit_on_success装饰器

        32678 Query UPDATE  a ...
        32678 Query commit

        32678 Query UPDATE b ...
        32678 Query commit

让我们理清这个流程:

  • django 默认模式是每个查询都是一个事务,默认模式会在a.save(), b.save()分别提交commit一次,这样就没有两个操作包在一起做事务的功能.所以我们使用了 transaction.commit_on_success 装饰器, 意味着全部操作成功才提交commit,而不是每个查询各自commit
  • 在view里面使用 transaction.commit_on_success, 使这个view的所有操作都是事务执行的
  • 由于django的读写db有设置db路由,使得读写db分别使用了不同的DB链接,看general_log看出来,读和写都有一个connect的操作 读id: 32455, 写id: 32466
  • id: 32466链接负责更新操作,成功之后commit完成事务,如果中途某个更新操作出错,将会回滚事务rollback

Savepoints

savepoint是一个可以让事务回滚到指定位置的标记, 默认的事务回滚时整个事务所有操作都回滚,这样开销会大,如果想回滚一部分,那就用savepoint标记某个位置,回滚的时候回到某个点

from django.db import transaction

@transaction.commit_manually
def viewfunc(request):

  a.save()
  # open transaction now contains a.save()
  sid = transaction.savepoint()

  b.save()
  # open transaction now contains a.save() and b.save()

  if want_to_keep_b:
      transaction.savepoint_commit(sid)
      # open transaction still contains a.save() and b.save()
  else:
      transaction.savepoint_rollback(sid)
      # open transaction now contains only a.save()

  transaction.commit()

Mysql 事务

MySQL默认操作模式就是autocommit自动提交模式。这就表示除非显式地开始一个事务,否则每个查询都被当做一个单独的事务自动执行。我们可以通过设置autocommit的值改变是否是自动提交autocommit模式。
通过以下命令可以查看当前autocommit模式

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.04 sec)
从查询结果中,我们发现Value的值是ON,表示autocommit开启。我们可以通过以下SQL语句改变这个模式
1
mysql> set autocommit = 0;
值0和OFF都是一样的,当然,1也就表示ON。通过以上设置autocommit=0,则用户将一直处于某个事务中,直到执行一条commit提交或rollback语句才会结束当前事务重新开始一个新的事务。

你可能感兴趣的:(Django 事务详解)