@Transactional(事務講解)和springboot 整合事務

@Transactional(事務講解)和springboot 整合事務

概述

事務在編程中分為兩種:聲明式事務處理和編程式事務處理

編程式事務處理:編碼方式實現事務管理,常與模版類TransactionTemplate(推薦使用) 在業務代碼中實現事務。

可知編程式事務每次實現都要單獨實現,但業務量大功能複雜時,使用編程式事務無疑是痛苦的,而聲明式事務不同,聲明式事務屬於無侵入式,不會影響業務邏輯的實現。

聲明式事務處理:

聲明式事務實現方式主要有2種,一種為通過使用Spring的<tx:advice>定義事務通知與AOP相關配置實現,另為一種通過@Transactional實現事務管理實現,下面詳細說明2種方法如何配置,已經相關注意點

1)方式一,配置文件如下

單獨實現,但業務量大功能複雜時,使用編程式事務無疑是痛苦的,而聲明式事務

1)方式二(推薦),介紹如下

@Transactional 是聲明式事務管理 編程中使用的註解

添加位置

接口實現類或接口實現方法上,而不是接口類中

訪問權限:public 的方法才起作用

@Transactional 註解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者默認可見性的方法上使用 @Transactional 註解

系統設計:將標籤放置在需要進行事務管理的方法上,而不是不假思索的放置在接口實現類上( 接口中所有方法都需要進行事務管理,但其實並不需要,如只讀的接口就不需要事務管理,但是 由於配置了@Transactional就需要AOP攔截及事務的處理,影響系統性能)

方法上註解屬性會覆蓋類註解上的相同屬性,當接口與接口中方法上同時帶有@Transactional註解時

錯誤使用:

接口中A、B兩個方法,A無@Transactional標籤,B有,上層通過A間接調用B,此時事務不生效

接口中異常(運行時異常)被捕獲而沒有被拋出

默認配置下,spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾),而拋出checked異常則不會導致事務回滾

可通過 @Transactional rollbackFor進行配置

多線程下事務管理

因為線程不屬於spring託管,故線程不能夠默認使用spring的事務,也不能獲取spring注入的bean

在被spring聲明式事務管理的方法內開啟多線程,多線程內的方法不被事務控制

一個使用了@Transactional 的方法,如果方法內包含多線程的使用,方法內部出現異常,不會回滾線程中調用方法的事務

聲明式事務管理實現方式:

  • 基於tx和aop名字空間的xml配置文件
推薦使用)在業務代碼中實現事務。可知編程式事務每次實現都要

基於@Transactional註解

@Transactional實質是使用了JDBC的事務來進行事務控制的

@Transactional基於Spring的動態代理的機制

@Transactional實現原理

1)事務開始時,通過AOP機制,生成一個代理connection對象,並將其放入DataSource實例的某個與DataSourceTransactionManager相關的某處容器中。在接下來的整個事務中,客戶代碼都應該使用該connection連接資料庫,執行所有資料庫命令[不使用該connection連接資料庫執行的資料庫命令,在本事務回滾的時候得不到回滾](物理連接connection邏輯上新建一個會話session;DataSource與TransactionManager配置相同的數據源)

2)事務結束時,回滾在第1步驟中得到的代理connection對象上執行的資料庫命令,然後關閉該代理connection對象(事務結束後,回滾操作不會對已執行完畢的SQL操作命令起作用)

聲明式事務的管理實現本質:

事務的兩種開啟方式

顯示開啟start transaction | begin,通過 commit | rollback 結束事務

關閉資料庫中自動提交 autocommit set autocommit = 0;MySQL 默認開啟自動提交;通過手動提交或執行回滾操作來結束事務

Spring 關閉資料庫中自動提交:在方法執行前關閉自動提交,方法執行完畢後再開啟自動提交

編碼方式實現事務管理,常與模版類TransactionTemplate(

問題:

關閉自動提交後,若事務一直未完成,即未手動執行 commit 或 rollback 時如何處理已經執行過的SQL操作?

C3P0默認的策略是回滾任何未提交的事務

C3P0是一個開源的JDBC連接池,它實現了數據源和JNDI綁定,支持JDBC3規範和JDBC2的標準擴展。目前使用它的開源項目有Hibernate,Spring等

JNDI(Java Naming and Directory Interface,Java命名和目錄接口)是SUN公司提供的一種標準的Java命名系統接口,JNDI提供統一的客戶端API,通過不同的訪問提供者接口JNDI服務供應接口(SPI)的實現,由管理者將JNDI API映射為特定的命名服務和目錄系統,使得Java應用程式可以和這些命名服務和目錄服務之間進行交互

------------------------------------------ --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------

spring事務特性

  • spring所有的事務管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager接口
:聲明式事務處理和編程式事務處理編程式事務處理:
  • 事務的隔離級別:是指若干個並發
  • 的事務之間的隔離程度
  • @Transactional(isolation = Isolation.READ_UNCOMMITTED):讀取未提交數據(會出現髒讀, 不可重複讀) 基本不使用
  • @Transactional(isolation = Isolation.READ_COMMITTED):讀取已提交數據(會出現不可重複讀和幻讀)
  • @Transactional(isolation = Isolation.REPEATABLE_READ):可重複讀(會出現幻讀)
  • @Transactional(isolation = Isolation.SERIALIZABLE):串行化
  • 事務傳播行為:如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為
  • TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。這是默認值。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------
  • @Transactional 屬性配置
概述事務在編程中分為兩種

  • 說明:
  • value :主要用來指定不同的事務管理器;主要用來滿足在同一個系統中,存在不同的事務管理器。比如在Spring中,聲明了兩種事務管理器txManager1, txManager2.然後,用戶可以根據這個參數來根據需要指定特定的txManager.
  • value 適用場景:在一個系統中,需要訪問多個數據源或者多個資料庫,則必然會配置多個事務管理器的
  • REQUIRED_NEW和NESTED兩種不同的傳播機制的分別
  • REQUIRED_NEW:內部的事務獨立運行,在各自的作用域中,可以獨立的回滾或者提交;而外部的事務將不受內部事務的回滾狀態影響
  • ESTED的事務,基於單一的事務來管理,提供了多個保存點。這種多個保存點的機制允許內部事務的變更觸發外部事務的回滾。而外部事務在混滾之後,仍能繼續進行事務處理,即使部分操作已經被混滾。 由於這個設置基於JDBC的保存點,所以只能工作在JDBC的機制
  • rollbackFor : 讓受檢查異常回滾;即讓本來不應該回滾的進行回滾操作
  • noRollbackFor :忽略非檢查異常;即讓本來應該回滾的不進行回滾操作
  • 嵌套事務
  • 帶有事務的方法調用其他事務的方法,此時執行的情況取決配置的事務的傳播屬性
  • PROPAGATION_REQUIRES_NEW :
  • 啟動一個新的, 不依賴於環境的 「內部」 事務. 這個事務將被完全 commited 或 rolled back 而不依賴於外部事務, 它擁有自己的隔離範圍, 自己的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行.
  • PROPAGATION_NESTED :
  • 如果外部事務 commit, 嵌套事務也會被 commit;如果外部事務 roll back, 嵌套事務也會被 roll back 。
  • 開始一個 「嵌套的」 事務, 它是已經存在事務的一個真正的子事務. 嵌套事務開始執行時, 它將取得一個 savepoint. 如果這個嵌套事務失敗, 我們將回滾到此 savepoint. 嵌套事務是外部事務的一部分, 只有外部事務結束後它才會被提交
  • 關於Spring的事務Transactional,鎖同步,並發線程
  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
  • spring事務回滾規則
  • 指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常
  • spring事務管理器會捕捉任何未處理的異常,然後依據規則決定是否回滾拋出異常的事務
  • 默認配置下,spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾),而拋出checked異常則不會導致事務回滾。
  • 用 spring 事務管理器,由spring來負責資料庫的打開,提交,回滾.默認遇到運行期例外(throw new RuntimeException(「注釋」);)會回滾,即遇到不受檢查(unchecked)的例外時回滾;而遇到需要捕獲的例外(throw new Exception(「注釋」);)不會回滾,即遇到受檢查的例外(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需我們指定方式來讓事務回滾要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .如果讓unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
  • ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  • 注意事項:
  • @Transactional 使用位置 類上方、方法上方
  • Spring 建議不要在接口或者接口方法上使用該註解,因為這隻有在使用基於接口的代理時它才會生效
  • 當作用於類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標註來覆蓋類級別的定義。
  • 方法的訪問權限為 public
  • @Transactional 註解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。在 protected、private 或者默認可見性的方法上使用 @Transactional 註解,這將被忽略,也不會拋出任何異常
  • 默認情況下,只有來自外部的方法調用才會被AOP代理捕獲,也就是,類內部方法調用本類內部的其他方法並不會引起事務行為,即使被調用方法使用@Transactional註解進行修飾
  • 例如一:同一個類中方法,A方法未使用此標籤,B使用了,C未使用,A 調用 B , B 調用 C ;則外部調用A之後,B的事務是不會起作用的
  • 例如二:若是有上層(按照 Controller層、Service層、DAO層的順序)由Action 調用 Service 直接調用,發生異常會發生回滾;若間接調用,Action 調用 Service 中 的A 方法,A無@Transactional 註解,B有,A調用B,B的註解無效
  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
  • 其他
  • 事務方法的嵌套調用會產生事務傳播
  • spring 的事務管理是線程安全的
  • 父類的聲明的@Transactional會對子類的所有方法進行事務增強;子類覆蓋重寫父類方式可覆蓋其@Transactional中的聲明配置
  • 類名上方使用@Transactional,類中方法可通過屬性配置覆蓋類上的@Transactional配置;比如:類上配置全局是可讀寫,可在某個方法上改為只讀
  • 源碼閱讀
  • 如果程序代碼中由於歷史原因遺留了接口內部方法調用的錯誤實現,可以用AspectJ 取代 Spring AOP 代理
  • 透徹的掌握 Spring 中@transactional 的使用
  • Spring @Transactional工作原理詳解
  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
  • 參考資料
  • spring的@Transactional註解詳細用法
  • Spring中@Transactional用法深度分析之一
  • @Transactional事務幾點注意
  • spring @Transactional註解參數詳解
  • 深入分析@Transactional的用法
  • Spring @Transactional (一)
  • Spring @Transactional工作原理
  • @Transactional註解工作原理
  • DBMS
  • c3p0
  • JNDI
  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
  • 多線程事務管理
  • 描述
  • 因為線程不屬於spring託管,故線程不能夠默認使用spring的事務,也不能獲取spring注入的bean
  • 在被spring聲明式事務管理的方法內開啟多線程,多線程內的方法不被事務控制
  • 解決
  • 如果方法中調用多線程
  • 方法主題的事務不會傳遞到線程中
  • 線程中可以單獨調用Service接口,接口的實現方法使用@Transactional,保證線程內部的事務
  • 多線程實現的方法
  • 使用異步註解@Async的方法上再加上註解@Transactional,保證新線程調用的方法是有事務管理的
  • 原理
  • Spring中事務信息存儲在ThreadLocal變量中,變量是某個線程上進行的事務所特有的(這些變量對於其他線程中發生的事務來講是不可見的,無關的)
  • 單線程的情況下,一個事務會在層級式調用的Spring組件之間傳播
  • 在@Transactional註解的服務方法會產生一個新的線程的情況下,事務是不會從調用者線程傳播到新建線程的
  • 參考資料
  • Spring和線程:事務
  • spring 多線程事務的問題
  • --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- ---------------------
  • springBoot中使用事務
  • 1.在啟動類上開啟事務管理
@SpringBootApplication@MapperScan("net.xdclass.xdvideo.mapper")//開啟事務管理@EnableTransactionManagementpublic class XdvideoApplication { public static void main(String[] args) { SpringApplication.run(XdvideoApplication.class, args); }}
  • 2在方法上或者類上開啟事務
@Transactional(propagation = Propagation.REQUIRED) 或者加上其他屬性 在上面介紹的有
聲明:文章觀點僅代表作者本人,PTTZH僅提供信息發布平台存儲空間服務。
喔!快樂的時光竟然這麼快就過⋯
繼續其他精彩內容吧!
more