MySQL事務(wù)以及隔離級(jí)別

mysql事務(wù)以及隔離級(jí)別

1. 簡(jiǎn)介

MySQL 事務(wù)主要用于處理操作量大稳摄,復(fù)雜度高的數(shù)據(jù)稚字。比如說(shuō),在人員管理系統(tǒng)中,你刪除一個(gè)人員胆描,你即需要?jiǎng)h除人員的基本資料瘫想,也要?jiǎng)h除和該人員相關(guān)的信息,如信箱昌讲,文章等等国夜,這樣,這些數(shù)據(jù)庫(kù)操作語(yǔ)句就構(gòu)成一個(gè)事務(wù)剧蚣!

  • 在 MySQL 中只有使用了 Innodb 數(shù)據(jù)庫(kù)引擎的數(shù)據(jù)庫(kù)或表才支持事務(wù)支竹。
  • 事務(wù)處理可以用來(lái)維護(hù)數(shù)據(jù)庫(kù)的完整性,保證成批的 SQL 語(yǔ)句要么全部執(zhí)行鸠按,要么全部不執(zhí)行礼搁。
  • 事務(wù)用來(lái)管理 insert,update,delete 語(yǔ)句

2. 事務(wù)的基本要素ACID

一般來(lái)說(shuō),事務(wù)是必須滿足4個(gè)條件(ACID)::原子性(Atomicity目尖,或稱不可分割性)馒吴、一致性(Consistency)、隔離性(Isolation瑟曲,又稱獨(dú)立性)饮戳、持久性(Durability)。

  • 原子性:一個(gè)事務(wù)(transaction)中的所有操作洞拨,要么全部完成扯罐,要么全部不完成,不會(huì)結(jié)束在中間某個(gè)環(huán)節(jié)烦衣。事務(wù)在執(zhí)行過(guò)程中發(fā)生錯(cuò)誤歹河,會(huì)被回滾(Rollback)到事務(wù)開(kāi)始前的狀態(tài),就像這個(gè)事務(wù)從來(lái)沒(méi)有執(zhí)行過(guò)一樣花吟。
  • 一致性:在事務(wù)開(kāi)始之前和事務(wù)結(jié)束以后秸歧,數(shù)據(jù)庫(kù)的完整性沒(méi)有被破壞。這表示寫(xiě)入的資料必須完全符合所有的預(yù)設(shè)規(guī)則衅澈,這包含資料的精確度键菱、串聯(lián)性以及后續(xù)數(shù)據(jù)庫(kù)可以自發(fā)性地完成預(yù)定的工作。比如A向B轉(zhuǎn)賬今布,不可能A扣了錢(qián)经备,B卻沒(méi)收到。
  • 隔離性:數(shù)據(jù)庫(kù)允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)其數(shù)據(jù)進(jìn)行讀寫(xiě)和修改的能力部默,隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致弄喘。事務(wù)隔離分為不同級(jí)別,包括讀未提交(Read uncommitted)甩牺、讀提交(read committed)、可重復(fù)讀(repeatable read)和串行化(Serializable)累奈。
  • 持久性:事務(wù)完成后贬派,事務(wù)對(duì)數(shù)據(jù)庫(kù)的所有更新將被保存到數(shù)據(jù)庫(kù)急但,不能回滾。

3. 事務(wù)的并發(fā)問(wèn)題

  1. 臟讀:允許讀取未提交的臟數(shù)據(jù)搞乏,比如:事務(wù)A讀取了事務(wù)B更新的數(shù)據(jù)波桩,然后B回滾操作,那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)请敦;
  2. 不可重復(fù)讀:如果你在時(shí)間點(diǎn)t1讀取了一些記錄镐躲,在t2時(shí)間點(diǎn)也想重新讀取一樣的數(shù)據(jù)時(shí),這些記錄可能已經(jīng)被改變侍筛,或者消失萤皂,比如:事務(wù) A 多次讀取同一數(shù)據(jù),事務(wù) B 在事務(wù)A多次讀取的過(guò)程中匣椰,對(duì)數(shù)據(jù)作了更新并提交裆熙,導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時(shí),結(jié)果不一致禽笑。
  3. 幻讀:系統(tǒng)管理員A將數(shù)據(jù)庫(kù)中所有學(xué)生的成績(jī)從具體分?jǐn)?shù)改為ABCDE等級(jí)入录,但是系統(tǒng)管理員B就在這個(gè)時(shí)候插入了一條具體分?jǐn)?shù)的記錄搪柑,當(dāng)系統(tǒng)管理員A改結(jié)束后發(fā)現(xiàn)還有一條記錄沒(méi)有改過(guò)來(lái)油狂,就好像發(fā)生了幻覺(jué)一樣评甜,這就叫幻讀非迹。

不可重復(fù)讀的和幻讀很容易混淆火惊,不可重復(fù)讀側(cè)重于修改狼钮,幻讀側(cè)重于新增或刪除卧抗。解決不可重復(fù)讀的問(wèn)題只需鎖住滿足條件的行响逢,解決幻讀需要鎖表望蜡。

4. 事務(wù)的4種隔離級(jí)別

為了解決上面事務(wù)的并發(fā)問(wèn)題唤崭,sql標(biāo)準(zhǔn)提出了4種隔離級(jí)別,下面是每種隔離級(jí)別能夠解決的問(wèn)題對(duì)應(yīng)關(guān)系:

事務(wù)隔離級(jí)別 臟讀 不可重復(fù)讀 幻讀
read-uncommitted N N N
read-committed Y N N
repeatable-read(default) Y Y N
serializable Y Y Y

mysql的默認(rèn)隔離級(jí)別是Repeatable脖律。

查看系統(tǒng)級(jí)和會(huì)話級(jí)的隔離級(jí)別:

mysql> select @@global.tx_isolation,@@tx_isolation; 
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation  |
+-----------------------+-----------------+
| REPEATABLE-READ       | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set, 2 warnings (0.01 sec)

下面用例子說(shuō)明一下這四種隔離級(jí)別:

1. read-uncommitted

更改隔離級(jí)別為read-uncommitted:

mysql> set session tx_isolation='read-uncommitted';
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set, 1 warning (0.00 sec)

首先谢肾,準(zhǔn)備一些測(cè)試數(shù)據(jù):

mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   25 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

客戶端A:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   25 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

客戶端B:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set age=52 where name='zhangsan';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

客戶端A:

mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   52 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

可以看到,客戶端B的事務(wù)還沒(méi)有提交小泉,在客戶端A的事務(wù)內(nèi)就看到了更新的數(shù)據(jù)芦疏。

客戶端B:

mysql> rollback;
Query OK, 0 rows affected (0.02 sec)

客戶端A:

mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   25 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

由于客戶端B的事務(wù)回滾,客戶端A讀取的數(shù)據(jù)又變成了原始數(shù)據(jù)微姊,因此上一次客戶端A讀取的數(shù)據(jù)變成了臟數(shù)據(jù)酸茴。在并發(fā)事務(wù)中,這種讀取數(shù)據(jù)的問(wèn)題就叫做臟讀兢交。

2. read-commited

要解決上面的問(wèn)題薪捍,可以把數(shù)據(jù)庫(kù)的隔離級(jí)別改成read-commited。

客戶端A:

mysql> set session tx_isolation='read-committed';
Query OK, 0 rows affected, 1 warning (0.00 sec)

再按照上述步驟測(cè)試一下,發(fā)現(xiàn)臟讀問(wèn)題已經(jīng)解決酪穿,在事務(wù)B沒(méi)有commit之前凳干,事務(wù)A不會(huì)讀取到臟數(shù)據(jù)。

下面演示一下不可重復(fù)讀的問(wèn)題被济。

客戶端A:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   25 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

客戶端B:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set age=52 where name='zhangsan';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

客戶端A:

mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   52 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

可以看到在客戶端B的事務(wù)提交前后救赐,客戶端A讀取到的數(shù)據(jù)不一樣了。也就是重復(fù)讀取相同的數(shù)據(jù)有不同的結(jié)果只磷。

個(gè)人理解经磅,臟讀也屬于不可重復(fù)讀的一個(gè)范疇,只是臟讀在事務(wù)B未提交之前就導(dǎo)致兩次讀取數(shù)據(jù)不一樣钮追,不可重復(fù)讀在事務(wù)B提交之后導(dǎo)致兩次讀取結(jié)果不一樣预厌。還有就是臟讀之所以叫臟數(shù)據(jù),是因?yàn)檫@條數(shù)據(jù)沒(méi)有真正的在數(shù)據(jù)庫(kù)中保存過(guò)畏陕,這是事務(wù)的一個(gè)中間狀態(tài)配乓。而不可重復(fù)讀兩次讀取不同的數(shù)據(jù)實(shí)際都已經(jīng)存在于數(shù)據(jù)庫(kù)中了。

3. repeatable-read

要解決不可重復(fù)讀的問(wèn)題惠毁,可以將數(shù)據(jù)庫(kù)的隔離級(jí)別改為repeatable-read犹芹。

客戶端A:

mysql> set session tx_isolation='repeatable-read';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

再按照上述步驟測(cè)試一下,發(fā)現(xiàn)不可重復(fù)讀的問(wèn)題已經(jīng)解決鞠绰,在事務(wù)B沒(méi)有commit之后腰埂,事務(wù)A讀取的數(shù)據(jù)沒(méi)有變化,關(guān)閉這個(gè)事務(wù)重新打開(kāi)一個(gè)事務(wù)才會(huì)讀到更新后的數(shù)據(jù)蜈膨。

下面演示一下幻讀的問(wèn)題屿笼。

客戶端A:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   25 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

客戶端B:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into user values(6,'shell',30);
Query OK, 1 row affected (0.01 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

客戶端A:

mysql> insert into user values(6,'shell',30);
ERROR 1062 (23000): Duplicate entry '6' for key 'PRIMARY'
mysql> select * from user;
+----+----------+------+
| id | name     | age  |
+----+----------+------+
|  1 | zhangsan |   25 |
|  2 | lisi     |   26 |
|  3 | wangwu   |   27 |
|  4 | nike     |   28 |
|  5 | lucy     |   29 |
+----+----------+------+
5 rows in set (0.00 sec)

可以看到,對(duì)于客戶端A來(lái)說(shuō)翁巍,命名沒(méi)有id為6的數(shù)據(jù)驴一,但是還是插入失敗,再查詢一下還是沒(méi)有啊灶壶,感覺(jué)產(chǎn)生了幻覺(jué)肝断,這就是幻讀問(wèn)題〕哿荩幻讀和不可重復(fù)讀的區(qū)別在于胸懈,不可重復(fù)讀重點(diǎn)是更新后的讀取,幻讀重點(diǎn)是插入刪除這些操作恰响,解決不可重復(fù)讀趣钱,只需要對(duì)對(duì)應(yīng)的數(shù)據(jù)行加鎖就行了。解決幻讀則需要對(duì)整張表加鎖胚宦。

如果兩個(gè)事務(wù)B沒(méi)有提交之前事務(wù)A執(zhí)行插入會(huì)如何呢首有?我們來(lái)看一下:

客戶端A:

mysql> insert into user values(6,'shell',30);



可以看到如果插入的id和事務(wù)B一樣燕垃,那么事務(wù)A的操作會(huì)被阻塞,直到事務(wù)B提交commit后绞灼,才會(huì)報(bào)錯(cuò):

客戶端A:

mysql> insert into user values(8,'svn',32);




ERROR 1062 (23000): Duplicate entry '8' for key 'PRIMARY'

如果客戶端A插入到的數(shù)據(jù)事務(wù)B不沖突利术,那么會(huì)立即返回成功:

客戶端A:

mysql> insert into user values(9,'svn',32);
Query OK, 1 row affected (0.00 sec)

4. serializable

要解決幻讀的問(wèn)題,可以將數(shù)據(jù)庫(kù)的隔離級(jí)別改為serializable低矮。

客戶端A:

mysql> set session tx_isolation='serializable';
Query OK, 0 rows affected, 1 warning (0.00 sec)

再按照上述步驟測(cè)試一下,發(fā)現(xiàn)幻讀的問(wèn)題已經(jīng)解決被冒,當(dāng)事務(wù)B嘗試insert的事務(wù)军掂,被阻塞,也就是事務(wù)A將整張表鎖住了昨悼。直到事務(wù)A提交commit以后蝗锥,事務(wù)B的操作才會(huì)返回結(jié)果。

在這種情況下率触,只允許一個(gè)事務(wù)在執(zhí)行终议,其它事務(wù)必須等待這個(gè)事務(wù)執(zhí)行完后才能執(zhí)行。沒(méi)有并發(fā)葱蝗,只是單純的串行穴张。

5. 總結(jié)

  1. mysql中默認(rèn)事務(wù)隔離級(jí)別是可重復(fù)讀時(shí)并不會(huì)鎖住讀取到的行;
  2. 事務(wù)隔離級(jí)別為讀提交時(shí),寫(xiě)數(shù)據(jù)只會(huì)鎖住相應(yīng)的行;
  3. 事務(wù)隔離級(jí)別為可重復(fù)讀時(shí)两曼,如果有索引(包括主鍵索引)的時(shí)候皂甘,以索引列為條件更新數(shù)據(jù),會(huì)存在間隙鎖間隙鎖悼凑、行鎖偿枕、下一鍵鎖的問(wèn)題,從而鎖住一些行户辫;如果沒(méi)有索引渐夸,更新數(shù)據(jù)時(shí)會(huì)鎖住整張表;
  4. 事務(wù)隔離級(jí)別為串行化時(shí),讀寫(xiě)數(shù)據(jù)都會(huì)鎖住整張表;
  5. 隔離級(jí)別越高渔欢,越能保證數(shù)據(jù)的完整性和一致性墓塌,但是對(duì)并發(fā)性能的影響也越大,魚(yú)和熊掌不可兼得啊膘茎。對(duì)于多數(shù)應(yīng)用程序桃纯,可以優(yōu)先考慮把數(shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別設(shè)為Read Committed,它能夠避免臟讀取披坏,而且具有較好的并發(fā)性能态坦。盡管它會(huì)導(dǎo)致不可重復(fù)讀、幻讀這些并發(fā)問(wèn)題棒拂,在可能出現(xiàn)這類問(wèn)題的個(gè)別場(chǎng)合伞梯,可以由應(yīng)用程序采用悲觀鎖或樂(lè)觀鎖來(lái)控制玫氢。

參考:

http://www.runoob.com/mysql/mysql-transaction.html

https://www.cnblogs.com/huanongying/p/7021555.html

https://blog.csdn.net/taylor_tao/article/details/7063639

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谜诫,隨后出現(xiàn)的幾起案子漾峡,更是在濱河造成了極大的恐慌,老刑警劉巖喻旷,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件生逸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡且预,警方通過(guò)查閱死者的電腦和手機(jī)槽袄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锋谐,“玉大人遍尺,你說(shuō)我怎么就攤上這事′剔郑” “怎么了乾戏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)三热。 經(jīng)常有香客問(wèn)我鼓择,道長(zhǎng),這世上最難降的妖魔是什么康铭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任惯退,我火速辦了婚禮,結(jié)果婚禮上从藤,老公的妹妹穿的比我還像新娘催跪。我一直安慰自己,他們只是感情好夷野,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布懊蒸。 她就那樣靜靜地躺著,像睡著了一般悯搔。 火紅的嫁衣襯著肌膚如雪骑丸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
  • 那天妒貌,我揣著相機(jī)與錄音通危,去河邊找鬼。 笑死灌曙,一個(gè)胖子當(dāng)著我的面吹牛菊碟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播在刺,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逆害,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼头镊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起魄幕,我...
    開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤相艇,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后纯陨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體坛芽,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年翼抠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了靡馁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡机久,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赔嚎,到底是詐尸還是另有隱情膘盖,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布尤误,位于F島的核電站侠畔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏损晤。R本人自食惡果不足惜软棺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尤勋。 院中可真熱鬧喘落,春花似錦、人聲如沸最冰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)暖哨。三九已至赌朋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篇裁,已是汗流浹背沛慢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留达布,地道東北人团甲。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像往枣,于是被迫代替她去往敵國(guó)和親伐庭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子粉渠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容