事務(wù)的特性:ACID
事務(wù)的特性:要么完全執(zhí)行,要么都不執(zhí)行。不過要對事務(wù)進(jìn)行更深一步的理解殊霞,還要從事務(wù)的 4 個特性說起罐农,這 4 個特性用英文字母來表達(dá)就是 ACID。
- 1. A譬淳,也就是原子性(Atomicity)。原子的概念就是不可分割奋单,你可以把它理解為組成物質(zhì)的基本單位宛畦,也是我們進(jìn)行數(shù)據(jù)處理操作的基本單位瘸洛。
- 2. C,就是一致性(Consistency)刃永。一致性指的就是數(shù)據(jù)庫在進(jìn)行事務(wù)操作后货矮,會由原來的一致狀態(tài),變成另一種一致的狀態(tài)斯够。也就是說當(dāng)事務(wù)提交后囚玫,或者當(dāng)事務(wù)發(fā)生回滾后,數(shù)據(jù)庫的完整性約束不能被破壞读规。
- 3. I抓督,就是隔離性(Isolation)。它指的是每個事務(wù)都是彼此獨立的束亏,不會受到其他事務(wù)的執(zhí)行影響铃在。也就是說一個事務(wù)在提交之前,對其他事務(wù)都是不可見的碍遍。
- 4. 最后一個 D定铜,指的是持久性(Durability)。事務(wù)提交之后對數(shù)據(jù)的修改是持久性的怕敬,即使在系統(tǒng)出故障的情況下揣炕,比如系統(tǒng)崩潰或者存儲介質(zhì)發(fā)生故障,數(shù)據(jù)的修改依然是有效的东跪。因為當(dāng)事務(wù)完成畸陡,數(shù)據(jù)庫的日志就會被更新,這時可以通過日志虽填,讓系統(tǒng)恢復(fù)到最后一次成功的更新狀態(tài)丁恭。
ACID 可以說是事務(wù)的四大特性,在這四個特性中斋日,原子性是基礎(chǔ)牲览,隔離性是手段,一致性是約束條件桑驱,而持久性是我們的目的竭恬。原子性和隔離性比較好理解,這里我講下對一致性的理解(國內(nèi)很多網(wǎng)站上對一致性的闡述有誤熬的,具體你可以參考 Wikipedia 對Consistency的闡述)痊硕。
我之前講到過數(shù)據(jù)表的 7 種常見約束(對應(yīng) 04 篇)。這里指的一致性本身是由具體的業(yè)務(wù)定義的押框,也就是說岔绸,任何寫入數(shù)據(jù)庫中的數(shù)據(jù)都需要滿足我們事先定義的約束規(guī)則。
事務(wù)的控制
當(dāng)我們了解了事務(wù)的特性后,再來看下如何使用事務(wù)盒揉。我們知道 Oracle 是支持事務(wù)的晋被,而在 MySQL 中,則需要選擇適合的存儲引擎才可以支持事務(wù)刚盈。如果你使用的是 MySQL羡洛,可以通過 SHOW ENGINES 命令來查看當(dāng)前 MySQL 支持的存儲引擎都有哪些,以及這些存儲引擎是否支持事務(wù)藕漱。
你能看出在 MySQL 中欲侮,InnoDB 是支持事務(wù)的,而 MyISAM 存儲引擎不支持事務(wù)肋联。
看到這里威蕉,我們已經(jīng)對事務(wù)有了一定的了解,現(xiàn)在我們再來看下事務(wù)的常用控制語句都有哪些橄仍。
- 1. START TRANSACTION 或者 BEGIN韧涨,作用是顯式開啟一個事務(wù)。
- 2. COMMIT:提交事務(wù)侮繁。當(dāng)提交事務(wù)后虑粥,對數(shù)據(jù)庫的修改是永久性的。
- 3. ROLLBACK 或者 ROLLBACK TO [SAVEPOINT],意為回滾事務(wù)宪哩。意思是撤銷正在進(jìn)行的所有沒有提交的修改舀奶,或者將事務(wù)回滾到某個保存點。
- 4. SAVEPOINT:在事務(wù)中創(chuàng)建保存點斋射,方便后續(xù)針對保存點進(jìn)行回滾。一個事務(wù)中可以存在多個保存點但荤。
- 5. RELEASE SAVEPOINT:刪除某個保存點罗岖。
- 6. SET TRANSACTION,設(shè)置事務(wù)的隔離級別腹躁。
需要說明的是桑包,使用事務(wù)有兩種方式,分別為隱式事務(wù)和顯式事務(wù)纺非。隱式事務(wù)實際上就是自動提交哑了,Oracle 默認(rèn)不自動提交,需要手寫 COMMIT 命令烧颖,而 MySQL 默認(rèn)自動提交弱左,當(dāng)然我們可以配置 MySQL 的參數(shù):
mysql> set autocommit =0; // 關(guān)閉自動提交
mysql> set autocommit =1; // 開啟自動提交
我們看下在 MySQL 的默認(rèn)狀態(tài)下,下面這個事務(wù)最后的處理結(jié)果是什么:
CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO test SELECT '關(guān)羽';
COMMIT;
BEGIN;
INSERT INTO test SELECT '張飛';
INSERT INTO test SELECT '張飛';
ROLLBACK;
SELECT * FROM test;
在這個事務(wù)中炕淮,整個 SQL 一共執(zhí)行了 2 個事務(wù)拆火,第一個是插入“關(guān)羽”,提交后執(zhí)行成功,第二個是插入兩次“張飛”们镜,這里需要注意的是币叹,我們將 name 設(shè)置為了主鍵,也就是說主鍵的值是唯一的模狭,那么第二次插入“張飛”時就會產(chǎn)生錯誤颈抚,然后執(zhí)行 ROLLBACK 相當(dāng)于對事務(wù)進(jìn)行了回滾,所以我們看到最終結(jié)果只有一行數(shù)據(jù)嚼鹉,也就是第一個事務(wù)執(zhí)行之后的結(jié)果贩汉,即“關(guān)羽”。
那么如果我們進(jìn)行下面的操作又會怎樣呢反砌?
CREATE TABLE testn(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO testn SELECT '關(guān)羽';
COMMIT;
INSERT INTO testn SELECT '張飛';
INSERT INTO testn SELECT '張飛';
ROLLBACK;
SELECT * FROM testn;
你能看到這次數(shù)據(jù)是 2 行雾鬼,上一次操作我把兩次插入“張飛”放到一個事務(wù)里,而這次操作它們不在同一個事務(wù)里宴树,那么對于 MySQL 來說策菜,默認(rèn)情況下這實際上就是兩個事務(wù),因為在 autocommit=1 的情況下酒贬,MySQL 會進(jìn)行隱式事務(wù)又憨,也就是自動提交,因此在進(jìn)行第一次插入“張飛”后锭吨,數(shù)據(jù)表里就存在了兩行數(shù)據(jù)蠢莺,而第二次插入“張飛”就會報錯:
1062 - Duplicate entry '張飛' for key 'PRIMARY'
。
最后我們在執(zhí)行 ROLLBACK 的時候零如,實際上事務(wù)已經(jīng)自動提交了躏将,就沒法進(jìn)行回滾了。
同樣的我們再來看下這段代碼考蕾,你又能發(fā)現(xiàn)什么不同呢祸憋?
CREATE TABLE test(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
SET @@completion_type = 1;
BEGIN;
INSERT INTO test SELECT '關(guān)羽';
COMMIT;
INSERT INTO test SELECT '張飛';
INSERT INTO test SELECT '張飛';
ROLLBACK;
SELECT * FROM test;
你能看到還是相同的 SQL 代碼,只是我在事務(wù)開始之前設(shè)置了
SET @@completion_type = 1;
肖卧,結(jié)果就和我們第一次處理的一樣蚯窥,只有一個“關(guān)羽”。這是為什么呢塞帐?
這里我講解下 MySQL 中 completion_type 參數(shù)的作用拦赠,實際上這個參數(shù)有 3 種可能:
- 1. completion=0,這是默認(rèn)情況葵姥。也就是說當(dāng)我們執(zhí)行 COMMIT 的時候會提交事務(wù)荷鼠,在執(zhí)行下一個事務(wù)時,還需要我們使用 START TRANSACTION 或者 BEGIN 來開啟榔幸。
- 2. completion=1颊咬,這種情況下务甥,當(dāng)我們提交事務(wù)后,相當(dāng)于執(zhí)行了 COMMIT AND CHAIN喳篇,也就是開啟一個鏈?zhǔn)绞聞?wù)敞临,即當(dāng)我們提交事務(wù)之后會開啟一個相同隔離級別的事務(wù)(隔離級別會在下一節(jié)中進(jìn)行介紹)。
- 3. completion=2麸澜,這種情況下 COMMIT=COMMIT AND RELEASE挺尿,也就是當(dāng)我們提交后,會自動與服務(wù)器斷開連接炊邦。
在上面這段代碼里编矾,我使用了 completion=1,也就是說當(dāng)我提交之后馁害,相當(dāng)于在下一行寫了一個 START TRANSACTION 或 BEGIN窄俏。這時兩次插入“張飛”會被認(rèn)為是在同一個事務(wù)之內(nèi)的操作,那么第二次插入“張飛”就會導(dǎo)致事務(wù)失敗碘菜,而回滾也將這次事務(wù)進(jìn)行了撤銷凹蜈,所以你能看到的結(jié)果就只有一個“關(guān)羽”。
當(dāng)我們設(shè)置 autocommit=0 時忍啸,不論是否采用 START TRANSACTION 或者 BEGIN 的方式來開啟事務(wù)仰坦,都需要用 COMMIT 進(jìn)行提交,讓事務(wù)生效计雌,使用 ROLLBACK 對事務(wù)進(jìn)行回滾悄晃。
當(dāng)我們設(shè)置 autocommit=1 時,每條 SQL 語句都會自動進(jìn)行提交凿滤。
不過這時妈橄,如果你采用 START TRANSACTION 或者 BEGIN 的方式來顯式地開啟事務(wù),那么這個事務(wù)只有在 COMMIT 時才會生效翁脆,在 ROLLBACK 時才會回滾眷细。