Mysql事務

事務定義

一個事務會涉及大量的cpu操做和IO操做,這些操做會被打包成一個執行單元,要麼同時完成,要麼同時都不完成。面試

事務是一組原子性的sql命令或者說是一個獨立的工做單元,若是其中任何一條sql語句由於崩潰或者其餘緣由執行失敗,那麼該組全部的sql語句都不會執行。若是沒有顯示啓動事務,數據庫會根據autocommit的值,默認每條sql操做都會自動提交。sql

事務的特性ACID

原子性(A)

一個事務中的全部操做,要麼都完成,要麼都不執行,對於一個事務來講,不可能只執行其中的一部分。數據庫

一致性(C)

數據庫老是從一個一致性的狀態轉換到另外一個一致性的狀態安全

隔離性(I)

一個事務所作的修改在最終提交以前,對其餘事務是不可見的。多個事務之間的操做相互不影響。每下降一個事務的隔離級別都能提升數據庫的併發,但同時不安全性就增長了。關於事務的隔離級別後續還要詳細討論。這裏簡單介紹一下:bash

  • 讀未提交:其餘事務未提交就能夠讀。
  • 讀已提交:其餘事務只有提交了才能讀。
  • 可重複讀:只管本身啓動事務時候的狀態,不接受其餘事務的影響。
  • 串行化:按照順序提交事務保證了數據的安全性,但沒法實現併發。

持久性(D)

事務一旦提交,就要更新到數據庫中,不能回滾。就算服務器宕機,仍然須要在下次啓動的時候自動執行事務中的sql命令,體現到數據庫中。服務器

數據庫事務隔離界別

介紹

隔離界別 髒讀 不可重複讀 幻讀
未提交讀(Read uncommited) 可能 可能 可能
已提交讀(Read commited) 不可能 可能 可能
可重複讀(Repeatable read) 不可能 不可能 可能
串行化(Serializable) 不可能 不可能 不可能
  • 未提交讀(Read uncommited):容許髒讀,也就是可能讀取到其餘會話中未提交事務修改的數據。
  • 已提交讀(Read commited):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別。
  • 可重複讀(Repeatable read):可重複讀。在同一事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標準中,改級別消除了不可重複讀,但仍是存在幻象讀,但InnoDB解決了幻讀。
  • 串行化:徹底串行化的讀,每次讀都須要得到表級共享鎖,讀寫相互都會阻塞。

準備數據

準備一個帳戶表,表裏三個字段,分別是主鍵id,帳戶名和金額session

create table account(
	id int(11) not null auto_increment,
	customer_name varchar(255) not null,
	money decimal(10,2) not null,
	primary key(id),
	unique uni_name using btree (customer_name)
) ENGINE = 'InnoDB' AUTO_INCREMENT=10 COMMENT = '帳戶表';
複製代碼

驗證RU(未提交讀)

一、開啓兩個會話,設置隔離級別爲read uncommited併發

set session transaction isolation level read uncommitted;

select @@session.tx_isolation;
複製代碼


二、會話1開啓事務

三、會話2開啓事務並插入一條數據

四、會話1開始查詢數據庫,查到了會話2事務未提交的數據

五、會話2若是此時回滾了,會話1就查不到了

小結:在RU模式下,一個事務能夠讀取到另外一個未提交事務的數據,致使了髒讀。若是另外一個事務回滾了,就會形成數據的不一致性。RU是事務隔離級別中最低的。

RC(讀提交)

一、將會話1和會話2的隔離級別設置成讀提交模式性能

set session transaction isolation level read committed;
複製代碼

二、會話1和會話2都開啓事務,會話1查詢當前數據

三、會話2更新數據但未提交,會話1查詢當前數據仍是沒改

四、可是會話2此時事務提交,會話1查詢當前數據變了

小結:在RC模式下,咱們發現,當另外一個事務沒有提交數據修改時,當前事務時讀不到修改後的數據的,這就避免了讀未提交模式的髒讀。但有一個問題,在當前事務中,兩次select的數據不同,這就存在了不可重複讀的問題。PS:RC隔離級別是Oracle數據庫默認的隔離級別。ui

RR(可重複讀)

一、將會話1和會話2的隔離級別都設置成可重複讀

set session transaction isolation level repeatable read;
複製代碼

二、會話1開啓事務並查詢當前數據,會話2開啓事務並更新數據

三、此時會話1查詢數據仍是以前的數據

四、而後會話2提交事務,會話1查詢數據仍是以前的數據,這表示會話2的更改並無影響當前的事務,能夠重複讀取。

五、此時會話1提交當前事務,並再次讀取數據,發現其餘事務改了數據

小結:在RR模式下,咱們解決了不可重複讀的問題,即在這種隔離級別下,一個事務中咱們可以保證獲取同樣的數據(即便有其餘事務正在改當前的數據行)。可是沒法避免幻讀, 幻讀簡單的解釋就是在數據有新增的時候,也沒法保證兩次獲得的數據不一致可是不一樣數據庫對不一樣的RR級別有不一樣的實現,有時候加上間隙鎖來避免幻讀。

InnoDB解決了幻讀

結論

首先說結論:在RR的隔離級別下,InnoDB使用MVCC和next-key locks(間隙鎖)解決幻讀。MVCC解決的是普通讀(快照讀)的幻讀,間隙鎖解決的是當前讀狀況下的幻讀。

幻讀是什麼

(首先聲明:在RR模式下,引擎是InnoDB,沒法產生如下效果。)
一、事務1先執行,但未提交

start transaction;
update account set account=1000 where id>10;
複製代碼

結果爲:OK row xx表名成功影響多少行 二、事務2後執行,而且提交

start transaction;
insert into account(customer_name, money) values('李雲龍',10000);
commit;
複製代碼

三、事務1再select一下,結果集爲:

select * from account;
複製代碼

··· 李雲龍,10000
這時,事務1蒙了,不是已經將id>10的全部人的金額都更新成1000了嗎,怎麼多出一我的金額是10000?這是已提交事務2對事務1產生的影響,這個影響就叫作幻讀。

幻讀和不可重複讀的區別

不可重複讀:屢次讀取一條記錄,發現該記錄中某些列值被修改過。
幻讀:只要是說屢次讀取一個範圍內的記錄(包括直接查詢全部記錄結果或者作聚合統計),發現結果不一致(通常指的是記錄增多,記錄的減小應該也算是幻讀)。

怎麼解決幻讀

當前讀
所謂當前讀,指的是加鎖的select(S鎖或者X鎖),update或者delete語句。在RR的事務隔離級別下,數據庫會使用間隙鎖來鎖住本條記錄以及索引區間。例如:
select * from account where id>10 for update;鎖住的就是id=10的記錄以及id>10的這個區間範圍,避免範圍間插入記錄,以免產生幻影行記錄。
普通讀
由於普通讀是不會加鎖的讀,因此解決幻讀的手段是MVCC。MVCC會給每行元祖加一些輔助字段,記錄建立版本號和刪除版本號。在每個事務啓動的時候,都有一個惟一的遞增的版本號。每開啓一個新事務,事務的版本號就會遞增。MYSQL默認的隔離級別(可重複讀Repeatable Read)下,增刪改查就變成下面這樣:

  • select:讀取建立版本小於或等於當前事務版本號,而且刪除版本爲空或大於當前事務版本號的記錄。這樣能夠保證在讀取以前記錄是存在的。
  • insert:將當前事務的版本號保存至行的建立版本號。
  • update:新插入一行,並以當前事務版本號做爲新行的建立版本號,同時將原紀錄行的刪除版本號設置爲當前事務版本號。
  • delete:將當前事務版本號保存至行的刪除版本號。 有點繞,總結下來就是每行多了兩個版本號,一個建立版本號和一個刪除版本號,都是保存事務的版本號。下面舉個例子理解一下: 例如我插入一條記錄,事務id=1,那麼記錄以下:
id name createversion deleteversion
1 馬雲 1

若是我把name更新成劉強東,事務id=2,那麼記錄就變成

id name createversion deleteversion
1 馬雲 1 2
2 劉強東 2

=> 能夠看出,原來的元祖的deleteversion爲更新的這個事務的id,而且新增一條
若是刪除的話,假設事務id=3,刪除id=2的記錄

id name createversion deleteversion
1 馬雲 1 2
2 劉強東 2 3

關鍵點來了,若是我如今讀取的話,須要同時知足兩個條件:
一、讀取建立版本小於或等於當前事務的版本號,這意味着數據在這個事務以前被建立
二、刪除版本爲空或者大於當前事務版本號的記錄。這意味着刪除操做在這個事務以後發生
因此當事務1插入一條記錄,事物2更新這條記錄並刪除這條記錄以後,事務1再次查詢這條記錄,只有id=1的記錄知足這兩個條件,因此結果爲:(避免了幻讀)

id name createversion deleteversion
1 馬雲 1 2

串行化

全部事務串行執行,是最高的隔離級別,性能最差

總結

這篇文章就到這了,總的來講數據庫事務的四個特性ACID和四種隔離級別(RU,RC,RR,串行化)以及會產生的問題(髒讀、不可重複讀、幻讀)是面試的高頻問點,什麼東西都須要積累,而後反覆的溫習,這樣才能記憶和理解的更深入。

相關文章
相關標籤/搜索