資料庫中為什麼需要Implict Commit(隱式提交事務),implictcommit
先看一段SQL,最後一條SQL的輸出你認為是什嗎?
SET AUTOCOMMIT = 1;BEGIN;INSERT INTO t1 VALUES (1);CREATE TABLE t2 (pk int primary key);INSERT INTO t2 VALUES (2);ROLLBACK;SHOW TABLES;
答案是:t1, t2都存在!
mysql> show tables;+----------------+| Tables_in_test |+----------------+| t1 || t2 |+----------------+2 rows in set (0.00 sec)
更奇怪的是:t1中的1也插入成功了!
mysql> select * from t1;+----+| pk |+----+| 1 |+----+1 row in set (0.00 sec)
為什麼ROLLBACK沒有生效呢?答案是:
Implict Commit
執行CREATE TABLE語句前,之前的事務被隱式提交。因為AUTOCOMMIT=1,所以提交後也不會自動新建立任何事務,INSERT語句執行後立即提交,ROLLBACK不會作用在任何事務上,所以得到了我們最後看到的結果。
稍微改一下,讓AUTOCOMMIT=0,會怎樣呢?
SET AUTOCOMMIT = 0;BEGIN;INSERT INTO t1 VALUES (1);CREATE TABLE t2 (pk int primary key);INSERT INTO t2 VALUES (2);ROLLBACK;SHOW TABLES;
答案是:t1, t2都存在!插入到t1中的1被提交(插入成功)但插入到t2中得2被復原(沒有插入成功)。之所以t1中的1被提交,是因為CREATE TABLE導致ImplictCOMMIT(注意,是COMMIT,不是ROLLBACK哦!),執行INSERT的時候,會自動開啟一個新事務(AUTOCOMMIT=0的語義要求的行為)。所以t2中的2被ROLLBACK復原。
為什麼部分操作會導致Implict Commit?為什麼這樣設計?
為了保證直觀上的原子性。假設不做Implict Commit,看看上面的語句會怎樣:使用者的心理預期是復原t1的INSERT操作,以及t2的CREATE操作,INSERT操作。如果我們有能力做到這樣,那的確是很完美的。但實際上我們很難做到,特別是在分布式系統中更難!因為CREATE TABLE操作背後涉及到了大量的操作,不僅僅包括對核心表的操作,還包括大量記憶體資料結構的更新(如Schema),以及儲存系統的變更(如建立相應的資料區塊),工程上很難把這些操作做成原子的。
那麼,應該如何做呢?比較折中的方式就是跟使用者做一個約定:CREATE TABLE操作總預設COMMIT它之前的事務,這就是implict commit。
從MySQL文檔看,他們做這一塊的時候遇到了很多問題,至少在這裡踩過兩個坑。並且,隨著版本的進化,他們還不斷的讓更多語句能引發implict commit。到底哪些語句會引發implict commit,請參考MySQL文檔: http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html