Django 會在每次請求之前先執行
- SET AUTOCOMMIT = 0
- SET AUTOCOMMIT = 1
- SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
然後在執行我們需要的 CRUD 操作
上面的三步操作可以認為是預備操作(但是在 Django 的 ORM 日誌中不會記錄)。
你可能會疑惑,為什麼要先 SET AUTOCOMMIT = 0
再 SET AUTOCOMMIT = 1
呢?
這個問題換一個問法就是:Django 如何保證事務乾淨?
其實原因很簡單,就是為了連線複用
的時候清理掉上次事務殘留。
Mysql 的事務中有一個 隱式提交
提交的概念?
當我們在一個事務還沒提交或者回滾時就又使用START TRANSACTION或者BEGIN語句開啟了另一個事務時,會隱式的提交上一個事務,比如這樣:
BEGIN; SELECT ... # 事務中的一條語句 UPDATE ... # 事務中的一條語句 ... # 事務中的其它語句 BEGIN; # 此語句會隱式的提交前邊語句所屬於的事務
或者當前的autocommit系統變數的值為OFF,我們手動把它調為ON時,也會隱式的提交前邊語句所屬的事務。
或者使用LOCK TABLES、UNLOCK TABLES等關於鎖定的語句也會隱式的提交前邊語句所屬的事務。
當然,這個操作是為了連線複用
而存在的,但是 Django ORM 預設的行為是不需要連線複用的,因為預設是為每個 Request 單獨新建一個連線。
2021-11-28T04:47:39.604596Z 307 Connect root@192.168.31.100 on d_twitter_db using TCP/IP
2021-11-28T04:47:39.608104Z 307 Query SET AUTOCOMMIT = 0
2021-11-28T04:47:39.612552Z 307 Query SET AUTOCOMMIT = 1
2021-11-28T04:47:39.617432Z 307 Query SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
2021-11-28T04:47:39.622479Z 307 Query SELECT `tweets_tweet`.`id`, `tweets_tweet`.`user_id`, `tweets_tweet`.`content`, `tweets_tweet`.`created_at` FROM `tweets_tweet` WHERE `tweets_tweet`.`user_id` = 1
2021-11-28T04:47:39.627836Z 307 Quit
sqlalchemy 呢?如何處理上次事務的殘留?
就是把 Django ORM 的 SET AUTOCOMMIT = 0
替換為了 ROLLBACK