事務(Transaction)是由一系列對系統中數據進行訪問與更新的操做所組成的一個程序 執行邏輯單元(Unit)。數據庫
狹義上的事務特指數據庫事務。一方面,當多個應用程序併發訪問數據庫時,事務能夠在這些應用程序之間提供一個隔離方法,以防止彼此的操做互相干擾。session
另外一方面,事務爲數據庫操做序列提供了一個從失敗中恢復到正常狀態的方法, 同時提供了數據庫即便在異常狀態下仍能保持數據一致性的方法。多線程
事務具備四個特徵,分別足原子性(Atomicity )、一致性(Consistency )、隔離性(Isolation) 和持久性(Durability),簡稱爲事務的ACID特性。併發
一、原子性(Atomicity )
事務的原子性是指事務必須是一個原子的操做序列單元。事務中包含的各項操做在一次執行過程當中,只容許出現如下兩種狀態之一。
•所有成功執行。
•所有不執行。spa
任何一項操做失敗都將致使整個事務失敗,同時其餘已經被執行的操做都將被撤銷並回滾,只打全部的操做所有成功,整個事務纔算是成功完成。線程
二、一致性(Consistency )
事務的一致性是指事務的執行不能破壞數據庫數據的完整性和一致性,一個事務在執行以前和執行以後,數據庫都必須處於一致性狀態。也就是說,事務執行的結果必須是使數據庫從一個一致性狀態轉變到另外一個一致性狀態,所以當數據庫只包含成功事務提交 的結果時,就能說數據庫處於一致性狀態。而若是數據庫系統在運行過程當中發生故障, 有些事務還沒有完成就被迫中斷,這些未完成的事務對數據庫所作的修改有一部分已寫入物理數據庫,這時數據庫就處於一種不正確的狀態,或者說是不一致的狀態。code
三、隔離性(Isolation)
事務的隔離性是指在併發環境中,併發的事務是相互隔離的,一個事務的執行不能被其餘事務干擾。也就是說,不一樣的事務併發操縱相同的數據時,每一個事務都有各自完整的數據空間,即一個事務內部的操做及使用的數據對其餘併發事務是隔離的,併發執行的 各個事務之間不能互相干擾。對象
在標準SQL規範中,定義了 4個事務隔離級別,不一樣的隔離級別對事務的處理不一樣, 如未受權讀取、受權讀取、可重複讀取和串行化
①未受權讀取
未受權讀取也被稱爲讀未提交(Read Uncommitted),該隔離級別容許髒讀取,其隔離級別最低。換句話說,若是一個事務正在處理某一數據,並對其進行了更新,但同時還沒有完成事務,所以尚未進行事務提交,而與此同時,容許另外一個事務也可以訪問該數據。舉個例子來講,事務A和事務B同時進行,事務A在整個執行階段,會將某數據項的值從1開始,作一系列加法操做(好比說加1操做)直到變成10以後進行事務提交,此時,事務B可以看到這個數據項在事務A操做過程當中的全部中間值(如1變成二、2變成3等),而對這一系列的中間值的讀取就是未受權讀取。blog
②受權讀取
受權讀取也被稱爲讀已提交(Read Committed),它和未受權讀取很是相近,惟一的區別就是受權讀取只容許獲取已經被提交的數據。一樣以上面的例子來講,事務 A和事務同時進行,事務A進行與上述一樣的操做,此時,事務B沒法看到這個數據項在事務A操做過程當中的全部中間值,只能看到最終的10。事務
另外,若是說有一個事務C,和事務A進行很是相似的操做,只是事務C是將數據項從10加到 20,此時事務B也一樣能夠讀取到20,即受權讀取容許不可重複讀取。
③可重複讀取
可重複讀取(Repeatable Read),簡單地說,就是保證在事務處理過程當中,屢次讀取同一個數據時,其值都和事務開始時刻是一致的。所以該事務級別禁止了不可重複讀取和髒讀取,可是有可能出現幻影數據。所謂幻影數據,就是指一樣的事務操做,在先後兩個時間段內執行對同一個數據項的讀取,可能出現不一致的結果。在上面的例子,可重複讀取隔離級別可以保證事務B在第一次事務操做過程當中,始終對數據項讀取到 1,可是在下一次事務操做中,即便事務 B (注意,事務名字雖然相同,可是指的是另外一次事務操做)採用一樣的查詢方式,就吋能會讀取到10或20。
④串行化
串行化( Serializable)是最嚴格的事務隔離級別。它要求全部事務都被串行執行,即事務只能一個接一個地進行處理,不能併發執行。
四、持久性(Durability)
事務的持久性也被稱爲永久性,是指一個事務一旦提交,它對數據庫中對應數據的狀態變動就應該是永久性的。換句話說,一旦某個事務成功結束,那麼它對數據庫所作的更新就必須被永久保存下來——即便發生系統崩潰或機器宕機等故障,只要數據庫可以從新啓動,那麼必定可以將其恢復到事務成功結束時的狀態。
以上介紹完事務的四大特性(簡稱ACID),如今重點來講明下事務的隔離性,當多個線程都開啓事務操做數據庫中的數據時,數據庫系統要能進行隔離操做,以保證各個線程獲取數據的準確性,在介紹數據庫提供的各類隔離級別以前,咱們先看看若是不考慮事務的隔離性,會發生的幾種問題:
髒讀是指在一個事務處理過程裏讀取了另外一個未提交的事務中的數據。
當一個事務正在屢次修改某個數據,而在這個事務中這屢次的修改都還未提交,這時一個併發的事務來訪問該數據,就會形成兩個事務獲得的數據不一致。例如:用戶A向用戶B轉帳100元,對應SQL命令以下
update account set money=money+100 where name=’B’; (此時A通知B) update account set money=money - 100 where name=’A’;
當只執行第一條SQL時,A通知B查看帳戶,B發現確實錢已到帳(此時即發生了髒讀),
而以後不管第二條SQL是否執行,只要該事務不提交,則全部操做都將回滾,那麼當B之後再次查看帳戶時就會發現錢其實並無轉。
不可重複讀是指在對於數據庫中的某個數據,一個事務範圍內屢次查詢卻返回了不一樣的數據值,這是因爲在查詢間隔,被另外一個事務修改並提交了。
例如事務T1在讀取某一數據,而事務T2立馬修改了這個數據而且提交事務給數據庫,事務T1再次讀取該數據就獲得了不一樣的結果,發送了不可重複讀。
不可重複讀和髒讀的區別是,髒讀是某一事務讀取了另外一個事務未提交的髒數據,而不可重複讀則是讀取了前一事務提交的數據。
在某些狀況下,不可重複讀並非問題,好比咱們屢次查詢某個數據固然以最後查詢獲得的結果爲主。但在另外一些狀況下就有可能發生問題,例如對於同一個數據A和B依次查詢就可能不一樣,A和B就可能打起來了……
幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中全部的行的某個數據項作了從「1」修改成「2」的操做,這時事務T2又對這個表中插入了一行數據項,而這個數據項的數值仍是爲「1」而且提交給數據庫。而操做事務T1的用戶若是再查看剛剛修改的數據,會發現還有一行沒有修改,其實這行是從事務T2中添加的,就好像產生幻覺同樣,這就是發生了幻讀。
幻讀和不可重複讀都是讀取了另外一條已經提交的事務(這點就髒讀不一樣),所不一樣的是不可重複讀查詢的都是同一個數據項,而幻讀針對的是一批數據總體(好比數據的個數)。
如今來看看MySQL數據庫爲咱們提供的四種隔離級別:
① Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。
② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
③ Read committed (讀已提交):可避免髒讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何狀況都沒法保證。
以上四種隔離級別最高的是Serializable級別,最低的是Read uncommitted級別,固然級別越高,執行效率就越低。像Serializable這樣的級別,就是以鎖表的方式(相似於Java多線程中的鎖)使得其餘的線程只能在鎖外等待,因此平時選用何種隔離級別應該根據實際狀況。在MySQL數據庫中默認的隔離級別爲Repeatable read (可重複讀)。
在MySQL數據庫中,支持上面四種隔離級別,默認的爲Repeatable read (可重複讀);而在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的爲Read committed級別。
在MySQL數據庫中查看當前事務的隔離級別:
select @@tx_isolation;
在MySQL數據庫中設置事務的隔離 級別:
set [glogal | session] transaction isolation level 隔離級別名稱; set tx_isolation=’隔離級別名稱;’
例1:查看當前事務的隔離級別:
例2:將事務的隔離級別設置爲Read uncommitted級別:
或:
記住:設置數據庫的隔離級別必定要是在開啓事務以前!
若是是使用JDBC對數據庫的事務設置隔離級別的話,也應該是在調用Connection對象的setAutoCommit(false)方法以前。
調用Connection對象的setTransactionIsolation(level)便可設置當前連接的隔離級別,至於參數level,可使用Connection對象的字段:
在JDBC中設置隔離級別的部分代碼:
後記:隔離級別的設置只對當前連接有效。對於使用MySQL命令窗口而言,一個窗口就至關於一個連接,當前窗口設置的隔離級別只對當前窗口中的事務有效;
對於JDBC操做數據庫來講,一個Connection對象至關於一個連接,而對於Connection對象設置的隔離級別只對該Connection對象有效,與其餘連接Connection對象無關。