@Transactional 詳解-【推薦】


原文地址:https://blog.csdn.net/jiangyu1013/article/details/84397366

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

1 .添加位置

1)接口實現類或接口實現方法上,而不是接口類中。
2)訪問權限:public 的方法才起作用。@Transactional 注解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。
系統設計:將標簽放置在需要進行事務管理的方法上,而不是放在所有接口實現類上:只讀的接口就不需要事務管理,由於配置了@Transactional就需要AOP攔截及事務的處理,可能影響系統性能。

3)錯誤使用:

1.接口中A、B兩個方法,A無@Transactional標簽,B有,上層通過A間接調用B,此時事務不生效。
 
2.接口中異常(運行時異常)被捕獲而沒有被拋出。
  默認配置下,spring 只有在拋出的異常為運行時 unchecked 異常時才回滾該事務,
  也就是拋出的異常為RuntimeException 的子類(Errors也會導致事務回滾),
  而拋出 checked 異常則不會導致事務回滾 。可通過 @Transactional rollbackFor進行配置。
 
3.多線程下事務管理因為線程不屬於 spring 托管,故線程不能夠默認使用 spring 的事務,
  也不能獲取spring 注入的 bean 。
  在被 spring 聲明式事務管理的方法內開啟多線程,多線程內的方法不被事務控制。
  一個使用了@Transactional 的方法,如果方法內包含多線程的使用,方法內部出現異常,
  不會回滾線程中調用方法的事務。

2.聲明式事務管理實現方式:
基於 tx 和 aop 名字空間的 xml 配置文件

// 基本配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:task="http://www.springframework.org/schema/task" xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
                          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
                          http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
                          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
                          http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.1.xsd">
 
<bean name="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="shardingDataSource"></property>
    </bean>
 
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
 
// MyBatis 自動參與到 spring 事務管理中,無需額外配置,
只要 org.mybatis.spring.SqlSessionFactoryBean 引用的數據源與
DataSourceTransactionManager 引用的數據源一致即可,否則事務管理會不起作用。
 
// <annotation-driven> 標簽的聲明,
是在 Spring 內部啟用 @Transactional 來進行事務管理,使用 @Transactional 前需要配置。

3. @Transactional注解
@Transactional 實質是使用了 JDBC 的事務來進行事務控制的
@Transactional 基於 Spring 的動態代理的機制

@Transactional 實現原理:
 
1) 事務開始時,通過AOP機制,生成一個代理connection對象,
   並將其放入 DataSource 實例的某個與 DataSourceTransactionManager 相關的某處容器中。
   在接下來的整個事務中,客戶代碼都應該使用該 connection 連接數據庫,
   執行所有數據庫命令。
   [不使用該 connection 連接數據庫執行的數據庫命令,在本事務回滾的時候得不到回滾]
  (物理連接 connection 邏輯上新建一個會話session;
   DataSource 與 TransactionManager 配置相同的數據源)
 
2) 事務結束時,回滾在第1步驟中得到的代理 connection 對象上執行的數據庫命令,
   然后關閉該代理 connection 對象。
  (事務結束后,回滾操作不會對已執行完畢的SQL操作命令起作用)

4.聲明式事務的管理實現本質:
事務的兩種開啟方式:
      顯示開啟 start transaction | begin,通過 commit | rollback 結束事務
      關閉數據庫中自動提交 autocommit set autocommit = 0;MySQL 默認開啟自動提交;通過手動提交或執行回滾操作來結束事務


Spring 關閉數據庫中自動提交:在方法執行前關閉自動提交,方法執行完畢后再開啟自動提交

// org.springframework.jdbc.datasource.DataSourceTransactionManager.java 源碼實現
 // switch to manual commit if necessary. this is very expensive in some jdbc drivers,
 // so we don't want to do it unnecessarily (for example if we've explicitly
 // configured the connection pool to set it already).
 if (con.getautocommit()) {
     txobject.setmustrestoreautocommit(true);
     if (logger.isdebugenabled()) {
         logger.debug("switching jdbc connection [" + con + "] to manual commit");
     }
     con.setautocommit(false);
 }

問題:

關閉自動提交后,若事務一直未完成,即未手動執行 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應用程序可以和這些命名服務和目錄服務之間進行交互

-------------------------------------------------------------------------------------------------------------------------------
5. spring 事務特性
spring 所有的事務管理策略類都繼承自 org.springframework.transaction.PlatformTransactionManager 接口

public interface PlatformTransactionManager {
  TransactionStatus getTransaction(TransactionDefinition definition)
  throws TransactionException;
  void commit(TransactionStatus status) throws TransactionException;
  void rollback(TransactionStatus status) throws TransactionException;
}

事務的隔離級別:是指若干個並發的事務之間的隔離程度

1. @Transactional(isolation = Isolation.READ_UNCOMMITTED):讀取未提交數據(會出現臟讀,
 不可重復讀) 基本不使用
 
2. @Transactional(isolation = Isolation.READ_COMMITTED):讀取已提交數據(會出現不可重復讀和幻讀)
 
3. @Transactional(isolation = Isolation.REPEATABLE_READ):可重復讀(會出現幻讀)
 
4. @Transactional(isolation = Isolation.SERIALIZABLE):串行化

事務傳播行為:如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為

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

 

 

 上表字段說明:

1. value :主要用來指定不同的事務管理器;
   主要用來滿足在同一個系統中,存在不同的事務管理器。
   比如在Spring中,聲明了兩種事務管理器txManager1, txManager2.然后,
   用戶可以根據這個參數來根據需要指定特定的txManager.
 
2. value 適用場景:在一個系統中,需要訪問多個數據源或者多個數據庫,
   則必然會配置多個事務管理器的
 
3. REQUIRED_NEW:內部的事務獨立運行,在各自的作用域中,可以獨立的回滾或者提交;
   而外部的事務將不受內部事務的回滾狀態影響。
 
4. ESTED 的事務,基於單一的事務來管理,提供了多個保存點。
   這種多個保存點的機制允許內部事務的變更觸發外部事務的回滾。
   而外部事務在混滾之后,仍能繼續進行事務處理,即使部分操作已經被混滾。 
   由於這個設置基於 JDBC 的保存點,所以只能工作在 JDB C的機制。
 
5. rollbackFor:讓受檢查異常回滾;即讓本來不應該回滾的進行回滾操作。
 
6. noRollbackFor:忽略非檢查異常;即讓本來應該回滾的不進行回滾操作。

 

 

 

 

 

 

 

 

 6.其他:

1. 事務方法的嵌套調用會產生事務傳播。
2. spring 的事務管理是線程安全的
3. 父類的聲明的 @Transactional 會對子類的所有方法進行事務增強;
   子類覆蓋重寫父類方式可覆蓋其 @Transactional 中的聲明配置。
 
4. 類名上方使用 @Transactional,類中方法可通過屬性配置來覆蓋類上的 @Transactional 配置;
   比如:類上配置全局是可讀寫,可在某個方法上改為只讀。

 

 

如果不對運行時異常進行處理,那么出現運行時異常之后,要么是線程中止,要么是主程序終止。 
如果不想終止,則必須捕獲所有的運行時異常,決不讓這個處理線程退出。隊列里面出現異常數據了,正常的處理應該是把異常數據舍棄,然后記錄日志。不應該由於異常數據而影響下面對正常數據的處理。


非運行時異常是RuntimeException以外的異常,類型上都屬於Exception類及其子類。如IOException、SQLException等以及用戶自定義的Exception異常。對於這種異常,JAVA編譯器強制要求我們必需對出現的這些異常進行catch並處理,否則程序就不能編譯通過。所以,面對這種異常不管我們是否願意,只能自己去寫一大堆catch塊去處理可能的異常。

 

 

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

轉自:https://blog.csdn.net/mingyundezuoan/article/details/79017659 

https://www.cnblogs.com/clwydjgs/p/9317849.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM