日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

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

發布時間:2025/4/16 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 事务,Oracle,MySQL及Spring事务隔离级别 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

二、事務特性(4種):?
原子性 (atomicity):強調事務的不可分割;
一致性 (consistency):事務的執行的前后數據的完整性保持一致;
隔離性 (isolation):一個事務執行的過程中,不應該受到其他事務的干擾 ;
持久性(durability) :事務一旦結束,數據就持久到數據庫。

三、如果不考慮隔離性引發安全性問題:?
臟讀 :一個事務讀到了另一個事務的未提交的數據?
不可重復讀 :一個事務讀到了另一個事務已經提交的 update 的數據導致多次查詢結果不一致.?
虛幻讀 :一個事務讀到了另一個事務已經提交的 insert 的數據導致多次查詢結果不一致.

四、為了處理這些問題,SQL標準定義了以下幾種事務隔離級別

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

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

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

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

說明:

  1、SQL規范所規定的標準,不同的數據庫具體的實現可能會有些差異

  2、mysql中默認事務隔離級別是可重復讀時并不會鎖住讀取到的行

  3、事務隔離級別為讀提交時,寫數據只會鎖住相應的行

  4、事務隔離級別為可重復讀時,寫數據會鎖住整張表

  5、事務隔離級別為串行化時,讀寫數據都會鎖住整張表

   6、隔離級別越高,越能保證數據的完整性和一致性,但是對并發性能的影響也越大,魚和熊掌不可兼得啊。對于多數應用程序,可以優先考慮把數據庫系統的隔離級別設為Read Committed,它能夠避免臟讀取,而且具有較好的并發性能。盡管它會導致不可重復讀、幻讀這些并發問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。

?

五、Oracle,MySQL及Spring事務隔離級別

1. Oracle事務隔離級別(2種)

Oracle數據庫支持READ COMMITTED 和?SERIALIZABLE這兩種事務隔離級別。所以Oracle不支持臟讀

SQL標準所定義的默認事務隔離級別是SERIALIZABLE,但是Oracle 默認使用的是READ COMMITTED

設置隔離級別使用 SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

下面是oracle 設置SERIALIZABLE隔離級別一個示例:

左面是事務T1,右面是事務T2,因為T2級別為SERIALIZABLE,所以即使事務T1在提交了數據之后,事務T2還是看不到T1提交的數據,幻想讀和不可重復讀都不允許了。

那如何能查看到T1新增的記錄呢? 上面T1和T2是并發執行,在T1執行insert的時候事務T2已經開始了,因為T2級別是SERIALIZABLE,所以T2所查詢的數據集是T2事務開始前數據庫的數據。即事務T1在事務T2開始之后的insert和update操作的影響都不會影響事務T2。現在重新開啟一個事務T3 就可以看到T1新增的記錄了。

當下列事件發生時,事務就開始了:

1)連接到數據庫,并執行第一條DML語句

2)前一個事務結束后,又輸入了另一條DML語句

?

2.MySQL事務隔離級別(4種)

mysql默認的事務隔離級別為repeatable-read

?

實例說明MySQL各個隔離級別的情況

1)、讀未提交:

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

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

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

(4)一旦客戶端B的事務因為某種原因回滾,所有的操作都將會被撤銷,那客戶端A查詢到的數據其實就是臟數據:

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

2)、讀已提交

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

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

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

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

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

3)、可重復讀

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

(2)在客戶端A的事務提交之前,打開另一個客戶端B,更新表account并提交,客戶端B的事務居然可以修改客戶端A事務查詢到的行,也就是mysql的可重復讀不會鎖住事務查詢到的行,這一點出乎我的意料,sql標準中事務隔離級別為可重復讀時,讀寫操作要鎖行的,mysql居然沒有鎖,我了個去。在應用程序中要注意給行加鎖,不然你會以步驟(1)中lilei的balance為400作為中間值去做其他操作

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

(4)執行步驟(1),lilei的balance仍然是400與步驟(1)查詢結果一致,沒有出現不可重復讀的 問題;接著執行update balance = balance - 50 where id = 1,balance沒有變成400-50=350,lilei的balance值用的是步驟(2)中的350來算的,所以是300,數據的一致性倒是沒有被破壞,這個有點神奇,也許是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開啟事務,查詢表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開啟事務,新增一條數據,其中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計算balance之和,值為300+16000+2400=18700,沒有把客戶端B的值算進去,客戶端A提交后再計算balance之和,居然變成了19300,這是因為把客戶端B的600算進去了,站在客戶的角度,客戶是看不到客戶端B的,它會覺得是天下掉餡餅了,多了600塊,這就是幻讀,站在開發者的角度,數據的 一致性并沒有破壞。但是在應用程序中,我們得代碼可能會把18700提交給用戶了,如果你一定要避免這情況小概率狀況的發生,那么就要采取下面要介紹的事務隔離級別“串行化”

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)打開一個客戶端A,并設置當前事務模式為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)打開一個客戶端B,并設置當前事務模式為serializable,插入一條記錄報錯,表被鎖了插入失敗,mysql中事務隔離級別為serializable時會鎖表,因此不會出現幻讀的情況,這種隔離級別并發性極低,往往一個事務霸占了一張表,其他成千上萬個事務只有干瞪眼,得等他用完提交才可以使用,開發中很少會用到。

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事務隔離級別(5種)?
1)DEFAULT: 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.?
2)未提交讀(read uncommited) :臟讀,不可重復讀,虛讀都有可能發生 ;
3)已提交讀 (read commited):避免臟讀。但是不可重復讀和虛讀有可能發生 ;
4)可重復讀 (repeatable read) :避免臟讀和不可重復讀.但是虛讀有可能發生;
5)串行化的 (serializable) :避免以上所有讀問題.?

Oracle 默認:讀已提交
Mysql 默認:可重復讀?


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

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。