MySQL事務(wù)

什么是事務(wù)

數(shù)據(jù)庫事務(wù)(Database Transaction),就是并發(fā)控制的基本單位,是指作為單個邏輯工作單元執(zhí)行的一系列操作,其中的操作要么完全執(zhí)行,要么完全地不執(zhí)行。

以整個轉(zhuǎn)賬過程為例,我們希望轉(zhuǎn)賬和收賬操作要么同時成功,要么同時失敗。這時,事務(wù)就可以幫助我們。

數(shù)據(jù)庫事務(wù)具有ACID屬性

ACID

原子性(Atomicity)

原子性是指事務(wù)的所有操作要么全部完成,要么全部失敗。事務(wù)在執(zhí)行時發(fā)生錯誤的話,會回滾到事務(wù)開始前的狀態(tài)。

回滾

所有事務(wù)進(jìn)行的修改都會先記錄到這個回滾日志中,然后在對數(shù)據(jù)庫中的對應(yīng)行進(jìn)行寫入。

一致性(Consistency)

一致性是指事務(wù)執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。
保證數(shù)據(jù)庫一致性是指當(dāng)事務(wù)完成時,必須使所有數(shù)據(jù)都具有一致的狀態(tài)(如主鍵約束、外鍵約束以及一些約束檢查等等)。在關(guān)系型數(shù)據(jù)庫中,所有的規(guī)則必須應(yīng)用到事務(wù)的修改上,以便維護(hù)所有數(shù)據(jù)的完整性。

我的理解是,已轉(zhuǎn)賬為例,轉(zhuǎn)賬前后,轉(zhuǎn)賬和收賬人賬戶余額里存儲的數(shù)據(jù)都是數(shù)字,具體的數(shù)字會變化,但是數(shù)據(jù)類型始終都是數(shù)字,并且轉(zhuǎn)賬前后兩個賬戶的總余額應(yīng)當(dāng)不變。

隔離性(Isolation)

數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。

事務(wù)隔離性的四個級別

讀未提交 RAED UNCOMMITED

使用查詢語句不會加鎖,可能會讀到未提交的行,也就是臟讀(Dirty Read)。
比如說,現(xiàn)有空表。事務(wù)a向表中插入值1但未提交,事務(wù)b此時讀取表,卻讀到了1,這就是臟讀。

讀提交 READ COMMITED

只對記錄加記錄鎖,而不會在記錄之間加間隙鎖,所以允許新的記錄插入到被鎖定記錄的附近,所以再多次使用查詢語句時,可能得到不同的結(jié)果,即不可重復(fù)讀(Non-Repeatable Read)。
比如說在事務(wù)a中查詢了一張表,返回了一個結(jié)果;然后在事務(wù)b中修改了表中被查詢的數(shù)據(jù)并提交了,此時事務(wù)a再查詢這張表,查詢的結(jié)果則是事務(wù)b修改后的數(shù)據(jù),這樣事務(wù)a兩次相同查詢操作的返回結(jié)果卻不同,也就是不可重復(fù)讀。

可重復(fù)讀 REPEATABLE READ

多次讀取同一范圍的數(shù)據(jù)會返回第一次查詢的快照,不會返回不同的數(shù)據(jù)行,但是可能發(fā)生幻讀(Phantom Read)。
比如說,先在事務(wù)a中查詢空表,返回空;然后在事務(wù)a中向表中的主鍵列id添加值1并提交,再在事務(wù)a中查詢該表,仍然返回空,也就是說可以重復(fù)讀了。
但是,此時我們再在事務(wù)a中向表中id列插入1,則會出錯,因為表中已經(jīng)有id=1,然而我們讀到地結(jié)果卻是空,這就是幻讀。

串行化 SERIALIZABLE

InnoDB 隱式地將全部的查詢語句加上共享鎖,解決了幻讀的問題。

持久性(Durability)

再來了解ACDI特性的最后一個成員,持久性。持久性就是說事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。

事務(wù)的使用

事務(wù)控制語句:

  • 開啟一個事務(wù) BEGINSTART TRANSACTION ;
  • 提交事務(wù) COMMIT ,也可以使用 COMMIT WORK,二者是等價的;
  • 回滾事務(wù) ROLLBACK 也可以使用 ROLLBACK WORK,二者是等價的;
  • SAVEPOINT identifier,SAVEPOINT 允許在事務(wù)中創(chuàng)建一個保存點,一個事務(wù)中可以有多個 SAVEPOINT;
  • RELEASE SAVEPOINT identifier 刪除一個事務(wù)的保存點,當(dāng)沒有指定的保存點時,執(zhí)行該語句會拋出一個異常;
  • ROLLBACK TO identifier把事務(wù)回滾到標(biāo)記點;
  • SET TRANSACTION 用來設(shè)置事務(wù)的隔離級別。

MYSQL 事務(wù)處理主要有兩種方法:

1、用 BEGIN, ROLLBACK, COMMIT來實現(xiàn)

  • BEGIN 開始一個事務(wù)
  • ROLLBACK 事務(wù)回滾
  • COMMIT 事務(wù)確認(rèn)
    2、直接用 SET 來改變 MySQL 的自動提交模式:
  • SET AUTOCOMMIT=0 禁止自動提交
  • SET AUTOCOMMIT=1 開啟自動提交

例子

BEGIN;

INSERT INTO student
     VALUES (13, '霉霉', 39, '女');
     
ROLLBACK;

SELECT * FROM student;

INSERT INTO student
     VALUES (13, '霉霉', 39, '女');
     
INSERT INTO score
      VALUE (5, 13, 1001, 99);

COMMIT;

因為ROLLBACK語句,上面代碼中的查詢student語句返回的結(jié)果沒有id=13的記錄:

ROLLBACK語句后,又進(jìn)行了插入值的操作,再查看,發(fā)現(xiàn)均已成功添加:


MySQL默認(rèn)的隔離等級為REPEATABLE-READ,不能臟讀,可重復(fù)讀,有可能會幻讀。
現(xiàn)在開啟兩個事務(wù)舉例。

在上一個例子中已經(jīng)向student表中添加了id=13的記錄,id為主鍵。
現(xiàn)在事務(wù)a中向student表再插入id=13的記錄話,可想而知,會報錯:

-- 事務(wù)a

BEGIN;

INSERT INTO score
      VALUE (6, 13, 1001, 99);

INSERT INTO student
     VALUES (13, '霉霉', 39, '女');
     
COMMIT;


再在事務(wù)a中查詢score表:

-- 事務(wù)a
SELECT * FROM test.score;


再在事務(wù)b中查詢score表:

-- 事務(wù)b
SELECT * FROM test.score;


可以發(fā)現(xiàn),在事務(wù)b中查詢score表的結(jié)果,沒有id=6的記錄,因為當(dāng)前隔離等級不可臟讀,也就是說事務(wù)a中的INSERT INTO score操作沒有提交。這是因為后面student表的插值操作失敗了,事務(wù)的原子性決定`score·表的差值操作也不會被提交。

在事務(wù)a中將studentid為1的學(xué)生的名字改為Mere:

-- 事務(wù)a
UPDATE student
   SET name = 'Mere'
 WHERE id = 13;


再在事務(wù)b中查詢student表:

可以看到,事務(wù)b中該條記錄沒有被修改,這就是可重復(fù)讀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容