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里面的使用:
- 装饰器
@transaction.commit_on_success
def view():
a.save()
b.save()
return ...
- with用法
def func()
with transaction.commit_on_success():
a.save()
b.save()
return ...
执行查看mysql 的genernal_log
# django 根据db读写路由,使读和写各生成了一个connect 链接数据库
# 32455 这个是负责查询
32455 Connect root@172.16.30.17 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 root@172.16.30.17 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语句才会结束当前事务重新开始一个新的事务。
网友评论