Django 1.4 事務(wù)默認(rèn)模式是autocommit模式,每個(gè)查詢都相當(dāng)于一個(gè)事務(wù),每次查詢都直接提交commit事務(wù),
除非事務(wù)被禁止
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默認(rèn)事務(wù)模式,就是每個(gè)查詢都相當(dāng)于一個(gè)事務(wù),提交后自動(dòng)commit
- @transactioncommit_on_success() ((django 1.8: transaction.atomic() ) 自己控制view或者其他需要事務(wù)的代碼
- @transaction.commit_manually() 自己控制commit和rollback,所以代碼里面必須顯式調(diào)用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 ...
執(zhí)行查看mysql 的genernal_log
# django 根據(jù)db讀寫路由,使讀和寫各生成了一個(gè)connect 鏈接數(shù)據(jù)庫
# 32455 這個(gè)是負(fù)責(zé)查詢
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 這個(gè)是負(fù)責(zé)更新
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 這個(gè)是負(fù)責(zé)查詢 ,第二個(gè)查詢,依然使用32455這個(gè)鏈接
32455 Query SELECT ...from b where .`id` = 1
# 32456 依然使用這個(gè)32456鏈接來更新數(shù)據(jù)
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 如果兩個(gè)更新有任何出錯(cuò))
# 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
讓我們理清這個(gè)流程:
- django 默認(rèn)模式是每個(gè)查詢都是一個(gè)事務(wù),默認(rèn)模式會(huì)在a.save(), b.save()分別提交commit一次,這樣就沒有兩個(gè)操作包在一起做事務(wù)的功能.所以我們使用了 transaction.commit_on_success 裝飾器, 意味著全部操作成功才提交commit,而不是每個(gè)查詢各自commit
- 在view里面使用 transaction.commit_on_success, 使這個(gè)view的所有操作都是事務(wù)執(zhí)行的
- 由于django的讀寫db有設(shè)置db路由,使得讀寫db分別使用了不同的DB鏈接,看general_log看出來,讀和寫都有一個(gè)connect的操作 讀id: 32455, 寫id: 32466
- id: 32466鏈接負(fù)責(zé)更新操作,成功之后commit完成事務(wù),如果中途某個(gè)更新操作出錯(cuò),將會(huì)回滾事務(wù)rollback
Savepoints
savepoint是一個(gè)可以讓事務(wù)回滾到指定位置的標(biāo)記, 默認(rèn)的事務(wù)回滾時(shí)整個(gè)事務(wù)所有操作都回滾,這樣開銷會(huì)大,如果想回滾一部分,那就用savepoint標(biāo)記某個(gè)位置,回滾的時(shí)候回到某個(gè)點(diǎn)
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 事務(wù)
MySQL默認(rèn)操作模式就是autocommit自動(dòng)提交模式椰憋。這就表示除非顯式地開始一個(gè)事務(wù),否則每個(gè)查詢都被當(dāng)做一個(gè)單獨(dú)的事務(wù)自動(dòng)執(zhí)行橙依。我們可以通過設(shè)置autocommit的值改變是否是自動(dòng)提交autocommit模式证舟。
通過以下命令可以查看當(dāng)前autocommit模式
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.04 sec)
從查詢結(jié)果中窗骑,我們發(fā)現(xiàn)Value的值是ON,表示autocommit開啟创译。我們可以通過以下SQL語句改變這個(gè)模式
1
mysql> set autocommit = 0;
值0和OFF都是一樣的,當(dāng)然软族,1也就表示ON刷喜。通過以上設(shè)置autocommit=0立砸,則用戶將一直處于某個(gè)事務(wù)中,直到執(zhí)行一條commit提交或rollback語句才會(huì)結(jié)束當(dāng)前事務(wù)重新開始一個(gè)新的事務(wù)颗祝。