數據庫事務

說明:本文章屬於個人學習歸納總結,其中內容有摘自他人博客內容,嚴禁轉載。

數據庫事務:控制事務的隔離級別,保證數據的完整性,安全性,一致性,在此基礎上實現高性能訪問。

##msyql事務
1.mysql:傳統理解 mysql 中的一次操作過程(sql 執行)是一次事務。
2.mysql:那麼多個線程 同時操作 mysql 中的數據(同一條數據,一個範圍內數據)就叫併發事務。
3.mysql:數據庫層面使用不同的事務+   隔離級別來進行併發事務的控制,不同的隔離級別是因爲數據庫中內部鎖機制的使用方式不同,例如有的是在select完成之後立馬釋放鎖,有的是在整個事務commit 之後釋放鎖
。
--------------------------------------------------------------------------------------------------------------
##應用層事務
1.應用:其實每一個線程調用服務本質上也是事務。
2.應用:多個線程同時調用服務,叫併發調用服務,也可以叫併發事務。
3.應用:應用層應對併發事務(訪問)解決方案有同步(悲觀鎖)、樂觀鎖(無鎖CAS)。
​
作者:mark_rock
鏈接:https://www.imooc.com/article/17291?block_id=tuijian_wz

 

5.1 事務的四個屬性

1.原子性:(Undo log)

事務是由一個或一組相互關聯的SQL語句組成的,要麼全部成功,要麼全部失敗。

2. 一致性:(Undo log)

​ 對於數據庫的修改是一致的,即多個用戶查詢的數據是一致的。一致性主要由mysql日誌機制處理,它記錄數據的變化,爲事務恢復提供追蹤記錄。

3.隔離性:(鎖機制)

​ 每個事務都有自己的空間,和其他發生在系統的事務隔離開來,而且事務的結果只在他完全被執行時才能看到。

4.持久性:(Redo log)

​ 提交了這個事務之後對數據的修改是永久的。在Mysql中,如果系統崩潰,可以通過日誌,恢復到系統崩潰前最後一次提交事務的數據。

InnoDB實現原理:

事務的ACID是通過InnoDB日誌和鎖來保證。事務的隔離性是通過數據庫鎖的機制實現的,持久性是通過redo log(重做日誌)來實現,原子性和一致性是通過Undo log(撤銷日誌)來實現的。Undo log的原理很簡單,爲了滿足原子性,在操作任何數據之前,首先將數據備份到Undo log。然後對數據進行修改。如果執行錯誤或者用戶執行了rollback語句,系統可以利用Undo log中的額備份數據恢復到事務開始之前的狀態。

Redo log 記錄的是新數據的備份。在事務提交之前,只要將Redo log持久化,不需要將數據備份。系統崩潰時可以根據Redo log持久化的數據進行恢復即可。

 

 

5.2 事務隔離

不同隔離級別帶來的數據操作問題:
 1.髒讀:兩個事務,t1事務可以讀取到t2事務正在做更改的數據的中間狀態(t2事務執行過程中),而這個數據的更改有可能不會被持久化(commit),而是rollback,導致t1在同一事務內的兩次讀取同一行數據得到結果不同。
 2.不可重複讀:t1事務在整個事務執行過程中讀取某一條記錄多次,發現讀取的此條記錄不是每次都一樣。
 3.幻讀:t1事務在整個事務執行過程中讀取某一範圍內的數據,在第二次讀取時發現多了幾行或者少了幾行。
-----------------------------------------------------------------------------------------------
數據庫中的幾種隔離級別
read uncommited--讀未提交
    該隔離級別指即使一個事務的更新語句沒有提交,但是別的事務可以讀到這個改變,幾種異常情況都可能出現。極易出錯,沒有安全性可言,基本不會使用。
read committed --讀已提交
    該隔離級別指一個事務只能看到其他事務的已經提交的更新,看不到未提交的更新,消除了髒讀和第一類丟失更新,這是大多數數據庫的默認隔離級別,如Oracle,Sqlserver。
repeatable read --可重複讀
    該隔離級別指一個事務中進行兩次或多次同樣的對於數據內容的查詢,得到的結果是一樣的,但不保證對於數據條數的查詢是一樣的,只要存在讀改行數據就禁止寫,消除了不可重複讀和第二類更新丟失,這是Mysql數據庫的默認隔離級別。
serializable --序列化讀
     意思是說這個事務執行的時候不允許別的事務併發寫操作的執行.完全串行化的讀,只要存在讀就禁止寫,但可以同時讀,消除了幻讀。這是事務隔離的最高級別,雖然最安全最省心,但是效率太低,一般不會用。
------------------------------------------------------------------------------------------------
數據庫中的鎖:
1.共享鎖(Share locks簡記爲S鎖):也稱讀鎖,事務A對對象T加s鎖,其他事務也只能對T加S,多個事務可以同時讀,但不能有寫操作,直到A釋放S鎖。
​
2.排它鎖(Exclusivelocks簡記爲X鎖):也稱寫鎖,事務A對對象T加X鎖以後,其他事務不能對T加任何鎖,只有事務A可以讀寫對象T直到A釋放X鎖。
​
3.更新鎖(簡記爲U鎖):用來預定要對此對象施加X鎖,它允許其他事務讀,但不允許再施加U鎖或X鎖;當被讀取的對象將要被更新時,則升級爲X鎖,主要是用來防止死鎖的。因爲使用共享鎖時,修改數據的操作分爲兩步,首先獲得一個共享鎖,讀取數據,然後將共享鎖升級爲排它鎖,然後再執行修改操作。這樣如果同時有兩個或多個事務同時對一個對象申請了共享鎖,在修改數據的時候,這些事務都要將共享鎖升級爲排它鎖。這些事務都不會釋放共享鎖而是一直等待對方釋放,這樣就造成了死鎖。如果一個數據在修改前直接申請更新鎖,在數據修改的時候再升級爲排它鎖,就可以避免死鎖。
​
​
作者:mark_rock
鏈接:https://www.imooc.com/article/17291?block_id=tuijian_wz

 

5.2.1多線程操作數據庫出現的問題

Mysql存儲引擎是在表級別,存儲引擎主要包括1.MyISAM:不支持事務,用於只讀程序提高性能 2.InnoDB:支持ACID事務、行級鎖、併發 。Mysql 事務的默認級別是可重複讀。

mysql> show variables like'tx_isolation';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.01 sec)

創建一張表,設置引擎

CREATE TABLE `test`.`user`( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(20) NOT NULL , `account` DECIMAL , PRIMARY KEY (`id`)  )ENGINE=INNODB;

 

設置事務級別:

set tx_isolation='Read-uncommitted';

髒讀:

​ 一個事務讀取另一個事務中讀取到一個未提交的數據。(事務設置的隔離級別爲讀未提交(Read-uncommittred會出現髒讀))。

Mysql默認事務隔離級別爲可重複讀,避免了髒讀、不可重複讀。
數據A讀到了數據B的未提交車數據

 

不可重複讀:

​ 由於數據隔離,某個數據在一個事務範圍內多次查詢卻返回不同的數據值。

幻讀:

​ 第一個事務對一定範圍內的數據進行批量修改,第二個事務在這個範圍增加條數據,這時第一個事務會丟失對新增數據的修改。(由於數據隔離,第二個事務不可見第一個事務裏修改的數據。例如:name唯一的user表中,事務A中新增一條name=jack的數據,提交之後,在事務B中查不到該條記錄,但是新增卻是失敗的。這就是幻讀)。

幻讀

5.2.2 事務隔離級別

讀未提交(READ-UNCOMMITTED ):最低級別,任何情況都可以發生。

讀已提交(READ-COMMITTED ):可避免髒讀發生,事務A對數據做的修改,提交之後會對事務B可見。

可重複讀(REPEATABLE-READ ):可避免髒讀,不可重複讀。事務A對數據做的修改,提交之後,對於先於事務A開啓的事務是不可見的。

串行化(SERIALIZABLE ):最高的隔離級別,可避免髒讀,幻讀,不可重複讀,在這種隔離級別下,讀取的每行數據都會加鎖,會導致大量的鎖爭用,效率低下,性能差。

5.3 JDK事務

​ Spring並不直接管理事務,而是提供了多種事務管理器,他們將事務管理的職責委託給Hibernate或者JPA等持久化機制所提供的相關平臺框架的事務來實現。  Spring事務管理器的接口是org.springframework.transaction.PlatformTransactionManager,通過這個接口,Spring爲各個平臺如JDBC、Hibernate等都提供了對應的事務管理器

5.3.1 事務幾種實現方式

(1)編程式事務管理對基於 POJO 的應用來說是唯一選擇。我們需要在代碼中調用beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理。

(2)基於 TransactionProxyFactoryBean的聲明式事務管理

(3)基於 @Transactional 的聲明式事務管理

(4)基於Aspectj AOP配置事務

5.3.2 事務的傳播特性

事務傳播行爲就是多個事務方法調用時,如何定義方法間事務的傳播。Spring定義了7中傳播行爲:

(1)propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是Spring默認的選擇。

(2)propagation_supports:支持當前事務,如果沒有當前事務,就以非事務方法執行。

(3)propagation_mandatory:使用當前事務,如果沒有當前事務,就拋出異常。

(4)propagation_required_new:新建事務,如果當前存在事務,把當前事務掛起。

(5)propagation_not_supported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

(6)propagation_never:以非事務方式執行操作,如果當前事務存在則拋出異常。

(7)propagation_nested:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與propagation_required類似的操作。

事務的第一個方面是傳播行爲(propagation behavior)。當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運行,也可能開啓一個新事務,並在自己的事務中運行。Spring定義了七種傳播行爲:

傳播行爲 含義
PROPAGATION_REQUIRED 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啓動一個新的事務
PROPAGATION_SUPPORTS 表示當前方法不需要事務上下文,但是如果存在當前事務的話,那麼該方法會在這個事務中運行
PROPAGATION_MANDATORY 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常
PROPAGATION_REQUIRED_NEW 表示當前方法總是需要獨立的新事務,如果當前已存在事務,就會把當前事務掛起,直到新的事務提交或者回滾才恢復執行
PROPAGATION_NOT_SUPPORTED 表示當前方法不需要事務,如果當前存在事務,就把當前事務掛起。
PROPAGATION_NEVER 表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常。簡單點說, 一旦發現有事務存在,往下連進行都不進行,直接拋出異常
PROPAGATION_NESTED 如果當前存在事務,則在嵌套事務內執行,如果嵌套事務存在,並且外層事務拋出異常回滾,那麼內層事務必須回滾,反之,內層事務並不影響外層事務

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章