日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

事务,Oracle,MySQL及Spring事务隔离级别

發(fā)布時(shí)間:2025/4/16 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 事务,Oracle,MySQL及Spring事务隔离级别 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、什么是事務(wù):?
事務(wù)邏輯上的一組操作,組成這組操作的各個(gè)邏輯單元,要么一起成功,要么一起失敗.

二、事務(wù)特性(4種):?
原子性 (atomicity):強(qiáng)調(diào)事務(wù)的不可分割;
一致性 (consistency):事務(wù)的執(zhí)行的前后數(shù)據(jù)的完整性保持一致;
隔離性 (isolation):一個(gè)事務(wù)執(zhí)行的過程中,不應(yīng)該受到其他事務(wù)的干擾 ;
持久性(durability) :事務(wù)一旦結(jié)束,數(shù)據(jù)就持久到數(shù)據(jù)庫(kù)。

三、如果不考慮隔離性引發(fā)安全性問題:?
臟讀 :一個(gè)事務(wù)讀到了另一個(gè)事務(wù)的未提交的數(shù)據(jù)?
不可重復(fù)讀 :一個(gè)事務(wù)讀到了另一個(gè)事務(wù)已經(jīng)提交的 update 的數(shù)據(jù)導(dǎo)致多次查詢結(jié)果不一致.?
虛幻讀 :一個(gè)事務(wù)讀到了另一個(gè)事務(wù)已經(jīng)提交的 insert 的數(shù)據(jù)導(dǎo)致多次查詢結(jié)果不一致.

四、為了處理這些問題,SQL標(biāo)準(zhǔn)定義了以下幾種事務(wù)隔離級(jí)別

READ UNCOMMITTED(讀未提交): 不可重復(fù)讀,臟讀及幻讀都允許;

READ COMMITTED(不可重復(fù)讀):允許不可重復(fù)讀,不允許臟讀,允許幻讀;

REPEATABLE READ (可重復(fù)讀):不允許不可重復(fù)讀和臟讀,但允許幻讀;

SERIALIZABLE(串行化):不可重復(fù)讀,臟讀和幻讀都不允許。

說明:

  1、SQL規(guī)范所規(guī)定的標(biāo)準(zhǔn),不同的數(shù)據(jù)庫(kù)具體的實(shí)現(xiàn)可能會(huì)有些差異

  2、mysql中默認(rèn)事務(wù)隔離級(jí)別是可重復(fù)讀時(shí)并不會(huì)鎖住讀取到的行

  3、事務(wù)隔離級(jí)別為讀提交時(shí),寫數(shù)據(jù)只會(huì)鎖住相應(yīng)的行

  4、事務(wù)隔離級(jí)別為可重復(fù)讀時(shí),寫數(shù)據(jù)會(huì)鎖住整張表

  5、事務(wù)隔離級(jí)別為串行化時(shí),讀寫數(shù)據(jù)都會(huì)鎖住整張表

   6、隔離級(jí)別越高,越能保證數(shù)據(jù)的完整性和一致性,但是對(duì)并發(fā)性能的影響也越大,魚和熊掌不可兼得啊。對(duì)于多數(shù)應(yīng)用程序,可以優(yōu)先考慮把數(shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別設(shè)為Read Committed,它能夠避免臟讀取,而且具有較好的并發(fā)性能。盡管它會(huì)導(dǎo)致不可重復(fù)讀、幻讀這些并發(fā)問題,在可能出現(xiàn)這類問題的個(gè)別場(chǎng)合,可以由應(yīng)用程序采用悲觀鎖或樂觀鎖來控制。

?

五、Oracle,MySQL及Spring事務(wù)隔離級(jí)別

1. Oracle事務(wù)隔離級(jí)別(2種)

Oracle數(shù)據(jù)庫(kù)支持READ COMMITTED 和?SERIALIZABLE這兩種事務(wù)隔離級(jí)別。所以O(shè)racle不支持臟讀

SQL標(biāo)準(zhǔn)所定義的默認(rèn)事務(wù)隔離級(jí)別是SERIALIZABLE,但是Oracle 默認(rèn)使用的是READ COMMITTED

設(shè)置隔離級(jí)別使用 SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

下面是oracle 設(shè)置SERIALIZABLE隔離級(jí)別一個(gè)示例:

左面是事務(wù)T1,右面是事務(wù)T2,因?yàn)門2級(jí)別為SERIALIZABLE,所以即使事務(wù)T1在提交了數(shù)據(jù)之后,事務(wù)T2還是看不到T1提交的數(shù)據(jù),幻想讀和不可重復(fù)讀都不允許了。

那如何能查看到T1新增的記錄呢? 上面T1和T2是并發(fā)執(zhí)行,在T1執(zhí)行insert的時(shí)候事務(wù)T2已經(jīng)開始了,因?yàn)門2級(jí)別是SERIALIZABLE,所以T2所查詢的數(shù)據(jù)集是T2事務(wù)開始前數(shù)據(jù)庫(kù)的數(shù)據(jù)。即事務(wù)T1在事務(wù)T2開始之后的insert和update操作的影響都不會(huì)影響事務(wù)T2。現(xiàn)在重新開啟一個(gè)事務(wù)T3 就可以看到T1新增的記錄了。

當(dāng)下列事件發(fā)生時(shí),事務(wù)就開始了:

1)連接到數(shù)據(jù)庫(kù),并執(zhí)行第一條DML語句

2)前一個(gè)事務(wù)結(jié)束后,又輸入了另一條DML語句

?

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

mysql默認(rèn)的事務(wù)隔離級(jí)別為repeatable-read

?

實(shí)例說明MySQL各個(gè)隔離級(jí)別的情況

1)、讀未提交:

(1)打開一個(gè)客戶端A,并設(shè)置當(dāng)前事務(wù)模式為read uncommitted(未提交讀),查詢表account的初始值:

(2)在客戶端A的事務(wù)提交之前,打開另一個(gè)客戶端B,更新表account:

(3)這時(shí),雖然客戶端B的事務(wù)還沒提交,但是客戶端A就可以查詢到B已經(jīng)更新的數(shù)據(jù):

(4)一旦客戶端B的事務(wù)因?yàn)槟撤N原因回滾,所有的操作都將會(huì)被撤銷,那客戶端A查詢到的數(shù)據(jù)其實(shí)就是臟數(shù)據(jù):

(5)在客戶端A執(zhí)行更新語句update account set balance = balance - 50 where id =1,lilei的balance沒有變成350,居然是400,是不是很奇怪,數(shù)據(jù)的一致性沒問啊,如果你這么想就太天真 了,在應(yīng)用程序中,我們會(huì)用400-50=350,并不知道其他會(huì)話回滾了,要想解決這個(gè)問題可以采用讀已提交的隔離級(jí)別

2)、讀已提交

(1)打開一個(gè)客戶端A,并設(shè)置當(dāng)前事務(wù)模式為read committed(未提交讀),查詢表account的初始值:

(2)在客戶端A的事務(wù)提交之前,打開另一個(gè)客戶端B,更新表account:

(3)這時(shí),客戶端B的事務(wù)還沒提交,客戶端A不能查詢到B已經(jīng)更新的數(shù)據(jù),解決了臟讀問題:

(4)客戶端B的事務(wù)提交

(5)客戶端A執(zhí)行與上一步相同的查詢,結(jié)果與上一步不一致,即產(chǎn)生了不可重復(fù)讀的問題,在應(yīng)用程序中,假設(shè)我們處于客戶端A的會(huì)話,查詢到lilei的balance為450,但是其他事務(wù)將lilei的balance值改為400,我們并不知道,如果用450這個(gè)值去做其他操作,是有問題的,不過這個(gè)概率真的很小哦,要想避免這個(gè)問題,可以采用可重復(fù)讀的隔離級(jí)別

3)、可重復(fù)讀

(1)打開一個(gè)客戶端A,并設(shè)置當(dāng)前事務(wù)模式為repeatable read,查詢表account的初始值:

(2)在客戶端A的事務(wù)提交之前,打開另一個(gè)客戶端B,更新表account并提交,客戶端B的事務(wù)居然可以修改客戶端A事務(wù)查詢到的行,也就是mysql的可重復(fù)讀不會(huì)鎖住事務(wù)查詢到的行,這一點(diǎn)出乎我的意料,sql標(biāo)準(zhǔn)中事務(wù)隔離級(jí)別為可重復(fù)讀時(shí),讀寫操作要鎖行的,mysql居然沒有鎖,我了個(gè)去。在應(yīng)用程序中要注意給行加鎖,不然你會(huì)以步驟(1)中l(wèi)ilei的balance為400作為中間值去做其他操作

(3)在客戶端A執(zhí)行步驟(1)的查詢:

(4)執(zhí)行步驟(1),lilei的balance仍然是400與步驟(1)查詢結(jié)果一致,沒有出現(xiàn)不可重復(fù)讀的 問題;接著執(zhí)行update balance = balance - 50 where id = 1,balance沒有變成400-50=350,lilei的balance值用的是步驟(2)中的350來算的,所以是300,數(shù)據(jù)的一致性倒是沒有被破壞,這個(gè)有點(diǎn)神奇,也許是mysql的特色吧

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mysql> select * from account; +------+--------+---------+ | id | name | balance | +------+--------+---------+ | 1 | lilei |? 400 | | 2 | hanmei | 16000 | | 3 | lucy | 2400 | +------+--------+---------+ rows in set (0.00 sec) mysql> update account set balance = balance - 50 where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from account; +------+--------+---------+ | id | name | balance | +------+--------+---------+ | 1 | lilei |? 300 | | 2 | hanmei | 16000 | | 3 | lucy | 2400 | +------+--------+---------+ rows in set (0.00 sec)

(5) 在客戶端A開啟事務(wù),查詢表account的初始值

1 2 3 4 5 6 7 8 9 10 11 12 mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from account; +------+--------+---------+ | id | name | balance | +------+--------+---------+ | 1 | lilei | 300 | | 2 | hanmei | 16000 | | 3 | lucy | 2400 | +------+--------+---------+ rows in set (0.00 sec)

(6)在客戶端B開啟事務(wù),新增一條數(shù)據(jù),其中balance字段值為600,并提交

1 2 3 4 5 6 7 8 mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> insert into account values(4,'lily',600); Query OK, 1 row affected (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.01 sec)

(7) 在客戶端A計(jì)算balance之和,值為300+16000+2400=18700,沒有把客戶端B的值算進(jìn)去,客戶端A提交后再計(jì)算balance之和,居然變成了19300,這是因?yàn)榘芽蛻舳薆的600算進(jìn)去了,站在客戶的角度,客戶是看不到客戶端B的,它會(huì)覺得是天下掉餡餅了,多了600塊,這就是幻讀,站在開發(fā)者的角度,數(shù)據(jù)的 一致性并沒有破壞。但是在應(yīng)用程序中,我們得代碼可能會(huì)把18700提交給用戶了,如果你一定要避免這情況小概率狀況的發(fā)生,那么就要采取下面要介紹的事務(wù)隔離級(jí)別“串行化”

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 mysql> select sum(balance) from account; +--------------+ | sum(balance) | +--------------+ | 18700 | +--------------+ 1 row in set (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select sum(balance) from account; +--------------+ | sum(balance) | +--------------+ | 19300 | +--------------+ 1 row in set (0.00 sec)

4).串行化

(1)打開一個(gè)客戶端A,并設(shè)置當(dāng)前事務(wù)模式為serializable,查詢表account的初始值:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mysql> set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select * from account; +------+--------+---------+ | id | name | balance | +------+--------+---------+ | 1 | lilei | 10000 | | 2 | hanmei | 10000 | | 3 | lucy | 10000 | | 4 | lily | 10000 | +------+--------+---------+ rows in set (0.00 sec)

(2)打開一個(gè)客戶端B,并設(shè)置當(dāng)前事務(wù)模式為serializable,插入一條記錄報(bào)錯(cuò),表被鎖了插入失敗,mysql中事務(wù)隔離級(jí)別為serializable時(shí)會(huì)鎖表,因此不會(huì)出現(xiàn)幻讀的情況,這種隔離級(jí)別并發(fā)性極低,往往一個(gè)事務(wù)霸占了一張表,其他成千上萬個(gè)事務(wù)只有干瞪眼,得等他用完提交才可以使用,開發(fā)中很少會(huì)用到。

1 2 3 4 5 6 7 8 mysql> set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> insert into account values(5,'tom',0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

3.Spring事務(wù)隔離級(jí)別(5種)?
1)DEFAULT: 這是一個(gè)PlatfromTransactionManager默認(rèn)的隔離級(jí)別,使用數(shù)據(jù)庫(kù)默認(rèn)的事務(wù)隔離級(jí)別.?
2)未提交讀(read uncommited) :臟讀,不可重復(fù)讀,虛讀都有可能發(fā)生 ;
3)已提交讀 (read commited):避免臟讀。但是不可重復(fù)讀和虛讀有可能發(fā)生 ;
4)可重復(fù)讀 (repeatable read) :避免臟讀和不可重復(fù)讀.但是虛讀有可能發(fā)生;
5)串行化的 (serializable) :避免以上所有讀問題.?

Oracle 默認(rèn):讀已提交
Mysql 默認(rèn):可重復(fù)讀?


read uncommited:是最低的事務(wù)隔離級(jí)別,它允許另外一個(gè)事務(wù)可以看到這個(gè)事務(wù)未提交的數(shù)據(jù)。?
read commited:保證一個(gè)事物提交后才能被另外一個(gè)事務(wù)讀取。另外一個(gè)事務(wù)不能讀取該事物未提交的數(shù)據(jù)。?
repeatable read:這種事務(wù)隔離級(jí)別可以防止臟讀,不可重復(fù)讀。但是可能會(huì)出現(xiàn)幻象讀。它除了保證一個(gè)事務(wù)不能被另外一個(gè)事務(wù)讀取未提交的數(shù)據(jù)之外還避免了以下情況產(chǎn)生(不可重復(fù)讀)。?
serializable:這是花費(fèi)最高代價(jià)但最可靠的事務(wù)隔離級(jí)別。事務(wù)被處理為順序執(zhí)行。除了防止臟讀,不可重復(fù)讀之外,還避免了幻象讀(避免三種)。

事務(wù)的傳播行為?
PROPAGION_XXX :事務(wù)的傳播行為?
* 保證同一個(gè)事務(wù)中?
PROPAGATION_REQUIRED 支持當(dāng)前事務(wù),如果不存在 就新建一個(gè)(默認(rèn))?
PROPAGATION_SUPPORTS 支持當(dāng)前事務(wù),如果不存在,就不使用事務(wù)?
PROPAGATION_MANDATORY 支持當(dāng)前事務(wù),如果不存在,拋出異常?
* 保證沒有在同一個(gè)事務(wù)中?
PROPAGATION_REQUIRES_NEW 如果有事務(wù)存在,掛起當(dāng)前事務(wù),創(chuàng)建一個(gè)新的事務(wù)?
PROPAGATION_NOT_SUPPORTED 以非事務(wù)方式運(yùn)行,如果有事務(wù)存在,掛起當(dāng)前事務(wù)?
PROPAGATION_NEVER 以非事務(wù)方式運(yùn)行,如果有事務(wù)存在,拋出異常?
PROPAGATION_NESTED 如果當(dāng)前事務(wù)存在,則嵌套事務(wù)執(zhí)行

總結(jié)

以上是生活随笔為你收集整理的事务,Oracle,MySQL及Spring事务隔离级别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。