一直很想對數據庫事務作一點總結,今天終於靜下心來小小的總結一下。 sql
1、數據庫事務的特徵 數據庫
一、原子性 瀏覽器
原子,顧名思義,天然界中的最小粒子(儘管物理上原子還可分割成夸克的什麼玩意,這個咱們就無論了)。定義一組操做集合,若是隻執行一個子集,這就破壞的事務的目標,事務必須不可分割,要麼所有執行,要麼所有不執行。 安全
二、一致性 session
在事務完成時,全部數據必須保持一致的狀態。例如:張三給李四轉帳100,元,張三帳號扣除了100,而李四帳號卻沒有變化,這就違背了一致性。 多線程
三、隔離性 併發
多用戶操做同一條數據時,必須時相互隔離,以避免A用戶操做影響了B用戶.。 分佈式
四、持久性 高併發
一個事務成功了,那麼就一定持久化到磁盤了,就算斷電了,下次重啓,數據依然正確無缺。 性能
2、幾個有趣的現象
不少時候,咱們習慣這樣描述咱們的系統,高併發、分佈式、集羣等等,對於一個多用戶、多線程的應用,不可避免的共同訪問相同的資源,若是沒有一套規則去約束這些操做,勢必要出亂子,這就是咱們要重點討論的事務隔離。
咱們先來看看幾個有趣現象:
一、髒讀
期末考過了半個月,小明正在急切的查分,一遍一遍的刷新着瀏覽器,數學分數怎麼還沒出來??碰巧數學老師在錄入分數,恰好錄到小明90分,提交請求,剛好小明刷新,90分,欣喜若狂。而此時數學老師發現錄入錯誤,撤銷了事務,小明再次查詢,分數消失,小明此時是各類猜想。
這個過程當中,有兩個事務在操做同一條數據:以下表,T表明時間
事務1
|
事務2
|
T1開啓事務
|
|
|
T2開啓事務
|
|
T3數學老師開始錄入分數90
|
T4小明查到分數90
|
|
|
T5老師發現錄入錯誤回滾數據
|
T6小明憂傷的查不到分數了
|
|
T7提交事務
|
|
很明顯,事務1讀到了事務2未提交的數據。
二、不可重複讀
最終小明查到了分數爲59,傷心的要準備補考了,準備把成績打印出來,發現打印出來的成績是69,原來老師發現有道題目解題思路新穎,要額外給小明加10分。
事務1 |
事務2 |
T1事務開啓 |
|
T2小明查到分數59 |
|
|
T3事務開啓 |
|
T4修改分數爲69 |
|
T5提交事務 |
T6小明打印成績69 |
|
T7提交事務 |
|
三、幻讀
小明一直在焦急的等待最後一門英語成績,發現始終沒有出來,便想把已經出來的成績先打印,最後發現打印出來的有英語成績。
事務1 |
事務2 |
T1事務開啓 |
|
T2小明查分,不包括英語 |
|
|
T3開啓事務 |
|
T4英語老師錄入分數 |
|
T5提交事務 |
T6小明打印到了英語成績 |
|
T7提交事務 |
|
注:有人要問了,不可重複讀和幻讀,一個德行,有什麼區別,不可重複讀是讀到了修改數據,幻讀是讀到了新增的數據,有又有什麼不一樣呢,數據庫的鎖不同,下次分享。
3、事務的隔離級別
以上的現象,不一樣的事務隔離級別,會產生對於的現象。
事務隔離級別:
一、讀未提交(READ-UNCOMMITTED);
二、讀已提交(READ-COMMITTED);
三、可重複讀(REPEATABLE-READ);
四、序列化(SERIABLIABLE)
隔離級別 |
髒讀 |
不可重複讀 |
幻讀 |
READ-UNCOMMITTED |
Y |
Y |
Y |
READ-COMMITTED |
N |
Y |
Y |
REPEATABLE-READ |
N |
N |
Y |
SERIALIZABLE |
N |
N |
N |
4、MySql的隔離級別和對應現象
Mysql默認的隔離級別是REPEATABLE-READ。
一、髒讀
(1)、設定數據庫隔離級別爲READ-UNCOMMITTED;
(2)、A事務開啓,查詢,沒查到數據;
(3)、B事務開啓,修改分數,但不提交;
(4)、A事務查詢,小明查到了分數90
(5)、B事務回滾
(6)、A事務再次查詢,已經查不到;
(7)、A事務提交;
下面咱們看把隔離級別設置成READ-COMMITTED可否解決這個問題。
(1)、設定隔離級別爲READ-COMMITTED;;
(2)、A事務查詢
(3)、B事務修改,但不提交;
(4)、A事務再次查詢,卻查詢不到;
(5)、B事務提交;
(6)、A事務再次查詢,查詢到了分數;
二、不可重複讀
緊接着上面的例子,上面的A事務還沒結束。
(1)、B事務再次修改分數提交;
(2)、A事務再次查詢;
那麼這個時候有同窗要問了,若是B事務沒有提交,有C事務來修改小明的分數會怎麼樣??下面咱們就來看看:
很明顯,C事務沒法修改這條記錄,這條記錄已經被加鎖。咱們略過這個小插曲。
兩次讀取的數據不同,這就是不可重複讀。讀到的是其餘事務已提交的數據,這也是無可厚非,固然有些系統特別變態要求可重複讀。
下面咱們看看REPEATABLE-READ,可否解決咱們的問題:
(1)、設定事務隔離級別爲REPEATABLE-READ;
(2)、A事務開啓,讀數據;
(3)、B事務開啓,修改數據,並提交;
(4)、A事務再次查詢,發現結果沒變;
很明顯,在REPEATABLE-READ級別下,A事務讀取數據是徹底不受其餘事務影響的,這就解決了不可重複讀的問題。
三、幻讀
緊接着上面的例子,事務A再次查詢,碰巧再次以前B事務新增了一條記錄,英語成績被錄入進來。
(1)、B事務新增一條記錄,並提交;
(2)、A事務再次查詢;
這裏有同窗就要奇怪了,爲何沒有查到英語成績,理論上要出現幻讀了,這是Why??
Mysql的可重複讀的實現和其餘數據庫是有區別的,不會形成幻讀,那麼仍是要說說幻讀,幻讀,就是同一個事務內,屢次查詢,讀取到其餘session 事務insert並已經提交的數據。
那麼咱們來看看最後一個隔離級別SERIALIZABLE。
(1)、設置隔離級別爲SERIALIZABLE
(2)、B事務開啓,新增記錄,並不提交;
(3)、A事務開啓事務查詢;
B事務沒提交,A事務就阻塞,就連select也會阻塞,這就是串行化得名的緣由,只能順序執行,全部安全級別最高,性能最低。
至於JDBC與隔離級別,請聽下回分解。