Spring中的事務

結合下文一起理解

數據庫常用的事務隔離級別

 

Spring事務的原理:

Spring中對事務支持實際上就是數據庫對事務的支持,它依賴於數據庫對事務性,只是利用Spring中AOP進行了事務的封裝,我們傳統的JDBC如果要開啓事務一般如下:

  1. 加載驅動
  2. 獲取連接對象Connection con = DriverManager.getConnection()
  3. con.setAutoCommit(false);
  4. 預處理sql語句preparestatment
  5. 設置佔位符
  6. 執行sql語句並得到查詢或者更新、結果
  7. 提交事務/回滾事務 con.commit() / con.rollback();
  8. 關閉連接(釋放資源)

Spring其實就是通過配置,生成代理對象,動態的爲我們執行了第3、7步

Spring中事務的使用:

1.SpringBoot中使用事務非常方便,直接在啓動類上添加註解@EnableTransactionManagement,在需要事務管理的方法上添加@Transactional即可
2.傳統的SSM中則需要配置:
xml文件中:

<!--開啓註解的方式--> 
<tx:annotation-driven transaction-manager="transactioManager" />

方法上使用@Transactional註解:

@Transactional(isolation=Isolation.DEFAULT)
public void fun(){
    dao.add();
    dao.udpate();
}

Spring支持的事務隔離等級


註解@Transactional裏的isolation屬性爲設置的事務隔離級別,Spring中支持五種配置:

TransactionDefinition.ISOLATION_DEFAULT: 使用後端數據庫默認的隔離級別,Mysql 默認採用的 REPEATABLE_READ隔離級別 Oracle 默認採用的 READ_COMMITTED隔離級別.
TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致髒讀、幻讀或不可重複讀
TransactionDefinition.ISOLATION_READ_COMMITTED: 允許讀取併發事務已經提交的數據,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生
TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生。
TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
第一種配置表示使用和數據庫一致的事務隔離級別,其他四種則分別對應了數據庫中四種隔離級別:讀未提交、讀已提交、可重複讀、串行化;

Spring中的傳播行爲:


Spring中規定了一些在嵌套事務的場景的配置,一共有7種:

TransactionDefinition.PROPAGATION_REQUIRED: 如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。
TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 創建一個新的事務,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式運行,如果當前存在事務,則把當前事務掛起。
TransactionDefinition.PROPAGATION_NEVER: 以非事務方式運行,如果當前存在事務,則拋出異常。
TransactionDefinition.PROPAGATION_NESTED: 如果當前存在事務,則創建一個事務作爲當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED

但一般我們只使用前兩個,假設外層事務 Service A 的 Method A() 調用 內層Service B 的 Method B()

        假設ServiceB.methodB() 的事務級別定義爲 PROPAGATION_REQUIRED,那麼執行 ServiceA.methodA() 的時候spring已經起了事務,這時調用 ServiceB.methodB(),ServiceB.methodB() 看到自己已經運行在 ServiceA.methodA() 的事務內部,就不再起新的事務。假如 ServiceB.methodB() 運行的時候發現自己沒有在事務中,他就會爲自己分配一個事務。
這樣,在 ServiceA.methodA() 或者在 ServiceB.methodB() 內的任何地方出現異常,事務都會被回滾。


        假設ServiceB.methodB() 的事務級別爲 PROPAGATION_SUPPORTS,那麼當執行到ServiceB.methodB()時,如果發現ServiceA.methodA()已經開啓了一個事務,則加入當前的事務,如果發現ServiceA.methodA()沒有開啓事務,則自己也不開啓事務。這種時候,內部方法的事務性完全依賴於最外層的事務。

 

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