Django ORM 和 sqlalchemy 在每次發起資料庫請求前對殘留事務的清理操作

ponponon發表於2021-11-28

Django 會在每次請求之前先執行

  • SET AUTOCOMMIT = 0
  • SET AUTOCOMMIT = 1
  • SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED

然後在執行我們需要的 CRUD 操作

上面的三步操作可以認為是預備操作(但是在 Django 的 ORM 日誌中不會記錄)。

你可能會疑惑,為什麼要先 SET AUTOCOMMIT = 0SET 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

相關文章