事務(wù)ACID特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability);
原子性是基礎(chǔ),隔離性是手段,持久性是目的,真正的老大就是一致性;
原子性(Atomicity):即事務(wù)是不可分割的最小工作單元,事務(wù)內(nèi)的操作要么全做,要么全不做;
一致性(Consistency):在事務(wù)執(zhí)行前數(shù)據(jù)庫的數(shù)據(jù)處于正確的狀態(tài),而事務(wù)執(zhí)行完成后數(shù)據(jù)庫的數(shù)據(jù)還是處于正確的狀態(tài),即數(shù)據(jù)完整性約束沒有被破壞;如銀行轉(zhuǎn)帳,A轉(zhuǎn)帳給B,必須保證A的錢一定轉(zhuǎn)給B,一定不會出現(xiàn)A的錢轉(zhuǎn)了但B沒收到,否則數(shù)據(jù)庫的數(shù)據(jù)就處于不一致(不正確)的狀態(tài)。
隔離性(Isolation):并發(fā)事務(wù)執(zhí)行之間無影響,在一個事務(wù)內(nèi)部的操作對其他事務(wù)是不產(chǎn)生影響,這需要事務(wù)隔離級別來指定隔離性;
持久性(Durability):事務(wù)一旦執(zhí)行成功,它對數(shù)據(jù)庫的數(shù)據(jù)的改變必須是永久的,不會因比如遇到系統(tǒng)故障或斷電造成數(shù)據(jù)不一致或丟失。
在實際項目開發(fā)中數(shù)據(jù)庫操作一般都是并發(fā)執(zhí)行的,即有多個事務(wù)并發(fā)執(zhí)行,并發(fā)執(zhí)行就可能遇到問題,目前常見的問題如下:
丟失更新:兩個事務(wù)同時更新一行數(shù)據(jù),最后一個事務(wù)的更新會覆蓋掉第一個事務(wù)的更新,從而導(dǎo)致第一個事務(wù)更新的數(shù)據(jù)丟失,這是由于沒有加鎖造成的;
臟讀:一個事務(wù)看到了另一個事務(wù)未提交的更新數(shù)據(jù);
不可重復(fù)讀:在同一事務(wù)中,多次讀取同一數(shù)據(jù)卻返回不同的結(jié)果;也就是有其他事務(wù)更改了這些數(shù)據(jù);
幻讀:一個事務(wù)在執(zhí)行過程中讀取到了另一個事務(wù)已提交的插入數(shù)據(jù);即在第一個事務(wù)開始時讀取到一批數(shù)據(jù),但此后另一個事務(wù)又插入了新數(shù)據(jù)并提交,此時第一個事務(wù)又讀取這批數(shù)據(jù)但發(fā)現(xiàn)多了一條,即好像發(fā)生幻覺一樣。
為了解決這些并發(fā)問題,需要通過數(shù)據(jù)庫隔離級別來解決,在標(biāo)準(zhǔn)SQL規(guī)范中定義了四種隔離級別:
未提交讀(Read Uncommitted):最低隔離級別,一個事務(wù)能讀取到別的事務(wù)未提交的更新數(shù)據(jù),很不安全,可能出現(xiàn)丟失更新、臟讀、不可重復(fù)讀、幻讀;
提交讀(Read Committed):一個事務(wù)能讀取到別的事務(wù)提交的更新數(shù)據(jù),不能看到未提交的更新數(shù)據(jù),不可能可能出現(xiàn)丟失更新、臟讀,但可能出現(xiàn)不可重復(fù)讀、幻讀;
可重復(fù)讀(Repeatable Read):保證同一事務(wù)中先后執(zhí)行的多次查詢將返回同一結(jié)果,不受其他事務(wù)影響,可能可能出現(xiàn)丟失更新、臟讀、不可重復(fù)讀,但可能出現(xiàn)幻讀;
序列化(Serializable):最高隔離級別,不允許事務(wù)并發(fā)執(zhí)行,而必須串行化執(zhí)行,最安全,不可能出現(xiàn)更新、臟讀、不可重復(fù)讀、幻讀。
隔離級別越高,數(shù)據(jù)庫事務(wù)并發(fā)執(zhí)行性能越差,能處理的操作越少。因此在實際項目開發(fā)中為了考慮并發(fā)性能一般使用提交讀隔離級別,它能避免丟失更新和臟讀,盡管不可重復(fù)讀和幻讀不能避免,但可以在可能出現(xiàn)的場合使用悲觀鎖或樂觀鎖來解決這些問題。
事務(wù)隔離級別(Transaction Isolation Level):
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE
從上往下,級別越來越高,并發(fā)性越來越差,安全性越來越高,反之則反。
事務(wù)隔離級別 ? ? ? ? ? ? ? ? ? ? ? ? ? ?臟讀 ? ? ? ? ? ? ? ? ? ? ?不可重復(fù)讀 ? ? ? ? ? ? ? ? 幻讀
READ_UNCOMMITTED ? ? ? ? ? ? 允許 ? ? ? ? ? ? ? ? ? ? ? 允許 ? ? ? ? ? ? ? ? ? ? ? 允許
READ_COMMITTED ? ? ? ? ? ? ? ? ?禁止 ? ? ? ? ? ? ? ? ? ? ? ? 允許 ? ? ? ? ? ? ? ? ? ? ? 允許
REPEATABLE_READ ? ? ? ? ? ? ? ? 禁止 ? ? ? ? ? ? ? ? ? ? ? ? ?禁止 ? ? ? ? ? ? ? ? ? ? ? ?允許
SERIALIZABLE ? ? ? ? ? ? ? ? ? ? ? ? 禁止 ? ? ? ? ? ? ? ? ? ? ? ? ? ? 禁止 ? ? ? ? ? ? ? ? ? ? ? 禁止
事務(wù)傳播行為(Transaction Propagation Behavior):
PROPAGATION_REQUIRED:如果當(dāng)前沒有事務(wù),就新建一個事務(wù),如果已經(jīng)存在一個事務(wù)中,加入到這個事務(wù)中。這是最常見的選擇。
RROPAGATION_REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
PROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則執(zhí)行與PROPAGATION_REQUIRED類似的操作。
PROPAGATION_SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
PROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
PROPAGATION_MANDATORY:使用當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。

并發(fā)控制:樂觀鎖-悲觀鎖
悲觀鎖:在關(guān)系數(shù)據(jù)庫管理系統(tǒng)里,悲觀并發(fā)控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種并發(fā)控制的方法。它可以阻止一個事務(wù)以影響其他用戶的方式來修改數(shù)據(jù)。如果一個事務(wù)執(zhí)行的操作都某行數(shù)據(jù)應(yīng)用了鎖,那只有當(dāng)這個事務(wù)把鎖釋放,其他事務(wù)才能夠執(zhí)行與該鎖沖突的操作。
悲觀并發(fā)控制主要用于數(shù)據(jù)爭用激烈的環(huán)境,以及發(fā)生并發(fā)沖突時使用鎖保護數(shù)據(jù)的成本要低于回滾事務(wù)的成本的環(huán)境中
悲觀鎖,正如其名,它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度(悲觀),因此,在整個數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。 悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制 (也只有數(shù)據(jù)庫層提供的鎖機制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))
優(yōu)點與不足
悲觀并發(fā)控制實際上是“先取鎖再訪問”的保守策略,為數(shù)據(jù)處理的安全提供了保證。但是在效率方面,處理加鎖的機制會讓數(shù)據(jù)庫產(chǎn)生額外的開銷,還有增加產(chǎn)生死鎖的機會;另外,在只讀型事務(wù)處理中由于不會產(chǎn)生沖突,也沒必要使用鎖,這樣做只能增加系統(tǒng)負(fù)載;還有會降低了并行性,一個事務(wù)如果鎖定了某行數(shù)據(jù),其他事務(wù)就必須等待該事務(wù)處理完才可以處理那行數(shù)
樂觀鎖
在關(guān)系數(shù)據(jù)庫管理系統(tǒng)里,樂觀并發(fā)控制(又名“樂觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種并發(fā)控制的方法。它假設(shè)多用戶并發(fā)的事務(wù)在處理時不會彼此互相影響,各事務(wù)能夠在不產(chǎn)生鎖的情況下處理各自影響的那部分?jǐn)?shù)據(jù)。在提交數(shù)據(jù)更新之前,每個事務(wù)會先檢查在該事務(wù)讀取數(shù)據(jù)后,有沒有其他事務(wù)又修改了該數(shù)據(jù)。如果其他事務(wù)有更新的話,正在提交的事務(wù)會進行回滾。樂觀事務(wù)控制最早是由孔祥重(H.T.Kung)教授提出。
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會造成沖突,所以在數(shù)據(jù)進行提交更新的時候,才會正式對數(shù)據(jù)的沖突與否進行檢測,如果發(fā)現(xiàn)沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。
相對于悲觀鎖,在對數(shù)據(jù)庫進行處理的時候,樂觀鎖并不會使用數(shù)據(jù)庫提供的鎖機制。一般的實現(xiàn)樂觀鎖的方式就是記錄數(shù)據(jù)版本。
數(shù)據(jù)版本,為數(shù)據(jù)增加的一個版本標(biāo)識。當(dāng)讀取數(shù)據(jù)時,將版本標(biāo)識的值一同讀出,數(shù)據(jù)每更新一次,同時對版本標(biāo)識進行更新。當(dāng)我們提交更新的時候,判斷數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息與第一次取出來的版本標(biāo)識進行比對,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的版本標(biāo)識值相等,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。
實現(xiàn)數(shù)據(jù)版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。
優(yōu)點與不足
樂觀并發(fā)控制相信事務(wù)之間的數(shù)據(jù)競爭(data race)的概率是比較小的,因此盡可能直接做下去,直到提交的時候才去鎖定,所以不會產(chǎn)生任何鎖和死鎖。但如果直接簡單這么做,還是有可能會遇到不可預(yù)期的結(jié)果,例如兩個事務(wù)都讀取了數(shù)據(jù)庫的某一行,經(jīng)過修改以后寫回數(shù)據(jù)庫,這時就遇到了問題。