精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Spring中事務的使用、抽象機制及模擬Spring事務實現

數據庫 其他數據庫
本文主要介紹了Spring中的事務相關內容,對Spring中的事務抽象機制做了介紹,然后帶著這些問題看源碼你才能知道Spring為什么要做這些事情!

本文大綱如下:

Spring事務應用大綱

編程式事務

Spring提供了兩種編程式事務管理的方法

  •  使用 TransactionTemplate 或者 TransactionalOperator.
  •  直接實現TransactionManager接口

如果是使用的是命令式編程,Spring推薦使用TransactionTemplate 來完成編程式事務管理,如果是響應式編程,那么使用TransactionalOperator更加合適。

TransactionTemplate

使用示例(我這里直接用的官網提供的例子了) 

  1. public class SimpleService implements Service {  
  2.     private final TransactionTemplate transactionTemplate;  
  3.      // 使用構造對transactionTemplate進行初始化  
  4.     // 需要提供一個transactionManager  
  5.     public SimpleService(PlatformTransactionManager transactionManager) {  
  6.         this.transactionTemplate = new TransactionTemplate(transactionManager);  
  7.     }  
  8.     public Object someServiceMethod() {  
  9.         return transactionTemplate.execute(new TransactionCallback() {  
  10.             public Object doInTransaction(TransactionStatus status) { 
  11.                  // 這里實現自己的相關業務邏輯  
  12.                 updateOperation1();  
  13.                 return resultOfUpdateOperation2();  
  14.             }  
  15.         });  
  16.     }  

在上面的例子中,我們顯示的使用了TransactionTemplate來完成事務管理,通過實現TransactionCallback接口并在其doInTransaction方法中完成了我們對業務的處理。我們可以大概看下TransactionTemplate的execute方法的實現: 

  1. public <T> T execute(TransactionCallback<T> action) throws TransactionException {  
  2.  Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");  
  3.  if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {  
  4.   return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);  
  5.  }  
  6.  else {  
  7.            // 1.通過事務管理器開啟事務  
  8.   TransactionStatus status = this.transactionManager.getTransaction(this);  
  9.   T result;  
  10.   try {  
  11.                // 2.執行傳入的業務邏輯  
  12.    result = action.doInTransaction(status);  
  13.   }  
  14.   catch (RuntimeException | Error ex) {  
  15.    // 3.出現異常,進行回滾  
  16.    rollbackOnException(status, ex);  
  17.    throw ex;  
  18.   }  
  19.   catch (Throwable ex) {  
  20.    // 3.出現異常,進行回滾  
  21.    rollbackOnException(status, ex);  
  22.    throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");  
  23.   }  
  24.            // 4.正常執行完成的話,提交事務  
  25.   this.transactionManager.commit(status);  
  26.   return result;  
  27.  }  

這些方法具體的實現我們暫且不看,后續進行源碼分析時都會詳細介紹,之所以將這個代碼貼出來是讓大家更好的理解TransactionTemplate的工作機制:實際上就是通過一個TransactionCallback封裝了業務邏輯,然后TransactionTemplate會在事務的上下文中調用。

在上面的例子中doInTransaction是有返回值的,而實際上有時候并不需要返回值,這種情況下,我們可以使用TransactionCallbackWithoutResult提代TransactionCallback。 

  1. transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
  2.     protected void doInTransactionWithoutResult(TransactionStatus status) {  
  3.         updateOperation1();  
  4.         updateOperation2();  
  5.     }  
  6. }); 

❝實際上我們還可以通過TransactionTemplate指定事務的屬性,例如隔離級別、超時時間、傳播行為等等

TransactionTemplate是線程安全的,我們可以全局配置一個TransactionTemplate,然后所有的類都共享這個TransactionTemplate。但是,如果某個類需要特殊的事務配置,例如需要定制隔離級別,那么我們就有必要去創建不同的TransactionTemplate。❞

TransactionOperator

❝TransactionOperator適用于響應式編程的情況,這里就不做詳細介紹了❞

TransactionManager

實際上TransactionTemplate內部也是使用TransactionManager來完成事務管理的,我們之前也看過它的execute方法的實現了,其實內部就是調用了TransactionManager的方法,實際上就是分為這么幾步

  1.  開啟事務
  2.  執行業務邏輯
  3.  出現異常進行回滾
  4.  正常執行則提交事務

這里我還是直接用官網給出的例子 

  1. // 定義事務  
  2. DefaultTransactionDefinition def = new DefaultTransactionDefinition();  
  3. def.setName("SomeTxName");  
  4. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  
  5. // txManager,事務管理器  
  6. // 通過事務管理器開啟一個事務  
  7. TransactionStatus status = txManager.getTransaction(def);  
  8. try {  
  9.     // 完成自己的業務邏輯  
  10.  
  11. catch (MyException ex) {  
  12.     // 出現異常,進行回滾  
  13.     txManager.rollback(status);  
  14.     throw ex;  
  15.  
  16. // 正常執行完成,提交事務  
  17. txManager.commit(status); 

我們在后邊的源碼分析中其實重點分析的也就是TransactionManager的源碼。

申明式事務

在對編程式事務有一定了解之后我們會發現,編程式事務存在下面幾個問題:

  1.  「我們的業務代碼跟事務管理的代碼混雜在一起」。
  2.  「每個需要事務管理的地方都需要寫重復的代碼」

如何解決呢?這就要用到申明式事務了,實現申明式事務一般有兩種方式

  •  基于XML配置
  •  基于注解

申明式事務事務的實現原理如下(圖片來源于官網):

實現原理

「實際上就是結合了APO自動代理跟事務相關API」。通過開啟AOP自動代理并向容器中注冊了事務需要的通知(Transaction Advisor),在Transaction Advisor調用了事務相關API,其實內部也是調用了TransactionManager的方法。

基于XML配置這種方式就不講了,筆者近兩年時間沒用過XML配置,我們主要就看看通過注解方式來實現申明式事務。主要涉及到兩個核心注解

  1.  @EnableTransactionManagement
  2.  @Transactional

@EnableTransactionManagement這個注解主要有兩個作用,其一是,開啟AOP自動代理,其二是,添加事務需要用到的通知(Transaction Advisor),如果你對AOP有一定了解的話那你應該知道一個Advisor實際上就是一個綁定了切點(Pointcut)的通知(Advice),通過@EnableTransactionManagement這個注解導入的Advisor所綁定的切點就是通過@Transactional來定義的。

申明式事務的例子我這里就省去了,我相信沒幾個人不會用吧.....

Spring對事務的抽象

Spring事務抽象的關鍵就是事務策略的概念,事務策略是通過TransactionManager接口定義的。TransactionManager本身只是一個標記接口,它有兩個直接子接口

  1.  ReactiveTransactionManager,這個接口主要用于在響應式編程模型下,不是我們要討論的重點
  2.  PlatformTransactionManager,命令式編程模型下我們使用這個接口。

❝關于響應式跟命令式編程都可以單獨寫一篇文章了,本文重點不是討論這兩種編程模型,可以認為平常我們使用的都是命令式編程❞

PlatformTransactionManager

PlatformTransactionManager接口定義 

  1. public interface PlatformTransactionManager extends TransactionManager {  
  2.  // 開啟事務  
  3.     TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;  
  4.     // 提交事務  
  5.     void commit(TransactionStatus status) throws TransactionException;  
  6.     // 回滾事務  
  7.     void rollback(TransactionStatus status) throws TransactionException;  

PlatformTransactionManager是命令式編程模型下Spring事務機制的中心接口,定義了完成一個事務必須的三個步驟,也就是說定義了事務實現的規范

  •  開啟事務
  •  提交事務
  •  回滾事務

通常來說,我們不會直接實現這個接口,而是通過繼承AbstractPlatformTransactionManager,這個類是一個抽象類,主要用作事務管理的模板,這個抽象類已經實現了事務的傳播行為以及跟事務相關的同步管理。

回頭看接口中定義的三個方法,首先是開啟事務的方法,從方法簽名上來看,其作用就是通過一個TransactionDefinition來獲取一個TransactionStatus類型的對象。為了更好的理解Spring中事務的抽象我們有必要了解下這兩個接口

TransactionDefinition

接口定義如下: 

  1. public interface TransactionDefinition {  
  2.      // 定義了7中事務的傳播機制  
  3.  int PROPAGATION_REQUIRED = 0 
  4.  int PROPAGATION_SUPPORTS = 1 
  5.  int PROPAGATION_MANDATORY = 2 
  6.  int PROPAGATION_REQUIRES_NEW = 3 
  7.  int PROPAGATION_NOT_SUPPORTED = 4 
  8.  int PROPAGATION_NEVER = 5 
  9.  int PROPAGATION_NESTED = 6 
  10.     // 4種隔離級別,-1代表的是使用數據庫默認的隔離級別  
  11.     // 比如在MySQL下,使用的就是ISOLATION_REPEATABLE_READ(可重復讀)  
  12.  int ISOLATION_DEFAULT = -1;  
  13.  int ISOLATION_READ_UNCOMMITTED = 1;    
  14.  int ISOLATION_READ_COMMITTED = 2;   
  15.  int ISOLATION_REPEATABLE_READ = 4;   
  16.  int ISOLATION_SERIALIZABLE = 8;     
  17.     // 事務的超時時間,默認不限制時間  
  18.  int TIMEOUT_DEFAULT = -1; 
  19.      // 提供了對上面三個屬性的get方法  
  20.  default int getPropagationBehavior() {  
  21.   return PROPAGATION_REQUIRED;  
  22.  }  
  23.  default int getIsolationLevel() {  
  24.   return ISOLATION_DEFAULT;  
  25.  }  
  26.  default int getTimeout() {  
  27.   return TIMEOUT_DEFAULT;  
  28.  }  
  29.     // 事務是否是只讀的,默認不是  
  30.  default boolean isReadOnly() {  
  31.   return false;  
  32.  }    
  33.     // 事務的名稱  
  34.  @Nullable  
  35.  default String getName() {  
  36.   return null;  
  37.  }    
  38.     // 返回一個只讀的TransactionDefinition  
  39.     // 只對屬性提供了getter方法,所有屬性都是接口中定義的默認值  
  40.  static TransactionDefinition withDefaults() {  
  41.   return StaticTransactionDefinition.INSTANCE;  
  42.  }  

從這個接口的名字上我們也能知道,它的主要完成了對事務定義的抽象,這些定義有些是數據庫層面本身就有的,例如隔離級別、是否只讀、超時時間、名稱。也有些是Spring賦予的,例如事務的傳播機制。Spring中一共定義了7種事務的傳播機制

  •  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這個注解去申明某個方法需要進行事務管理,在@Transactional中可以定義事務的屬性,這些屬性實際上就會被封裝到一個TransactionDefinition中,當然封裝的時候肯定不是直接使用的接口,而是這個接口的一個實現類RuleBasedTransactionAttribute。RuleBasedTransactionAttribute,該類的繼承關系如下:

RuleBasedTransactionAttribute

  •  DefaultTransactionDefinition,實現了TransactionDefinition,并為其中的定義的屬性提供了默認值   
  1. // 默認的傳播機制為required,沒有事務新建一個事務  
  2.     // 有事務的話加入當前事務  
  3.     private int propagationBehavior = PROPAGATION_REQUIRED 
  4.     // 隔離級別跟數據庫默認的隔離級別一直  
  5.     private int isolationLevel = ISOLATION_DEFAULT 
  6.     // 默認為-1,不設置超時時間  
  7.     private int timeout = TIMEOUT_DEFAULT 
  8.     // 默認不是只讀的  
  9.     private boolean readOnly = false
  •  TransactionAttribute,擴展了``DefaultTransactionDefinition`,新增了兩個事務的屬性   
  1. // 用于指定事務使用的事務管理器的名稱  
  2.     String getQualifier();  
  3.     // 指定在出現哪種異常時才進行回滾  
  4.     boolean rollbackOn(Throwable ex); 
  •  DefaultTransactionAttribute,繼承了DefaultTransactionDefinition,同時實現了TransactionAttribute接口,定義了默認的回滾異常 
  1. // 拋出RuntimeException/Error才進行回滾  
  2.   public boolean rollbackOn(Throwable ex) {  
  3.       return (ex instanceof RuntimeException || ex instanceof Error);  
  4.   } 
  •  RuleBasedTransactionAttribute,@Transactional注解的rollbackFor等屬性就會被封裝到這個類中,允許程序員自己定義回滾的異常,如果沒有指定回滾的異常,默認「拋出RuntimeException/Error才進行回滾」

TransactionStatus

這個接口主要用于描述Spring事務的狀態,其繼承關系如下:

TransactionStatus

  •  TransactionExecution,這個接口也是用于描述事務的狀態,TransactionStatus是在其上做的擴展,內部定義了以下幾個方法 
  1. // 判斷當前事務是否是一個新的事務  
  2.  // 不是一個新事務的話,那么需要加入到已經存在的事務中  
  3.  boolean isNewTransaction();  
  4.  // 事務是否被標記成RollbackOnly  
  5.  // 如果被標記成了RollbackOnly,意味著事務只能被回滾  
  6.  void setRollbackOnly();   
  7.  boolean isRollbackOnly();  
  8.  // 是否事務完成,回滾或提交都意味著事務完成了  
  9.  boolean isCompleted(); 
  •  SavepointManager,定義了管理保存點(Savepoint)的方法,隔離級別為NESTED時就是通過設置回滾點來實現的,內部定義了這么幾個方法   
  1. // 創建保存點  
  2.    Object createSavepoint() throws TransactionException;  
  3.    // 回滾到指定保存點  
  4.    void rollbackToSavepoint(Object savepoint) throws TransactionException;  
  5.    // 移除回滾點  
  6.    void releaseSavepoint(Object savepoint) throws TransactionException; 
  •  TransactionStatus,繼承了上面這些接口,額外提供了兩個方法   
  1. //用于判斷當前事務是否設置了保存點  
  2.    boolean hasSavepoint(); 
  3.    // 這個方法復寫了父接口Flushable中的方法  
  4.    // 主要用于刷新會話  
  5.    // 對于Hibernate/jpa而言就是調用了其session/entityManager的flush方法  
  6.    void flush(); 

❝小總結:通過上面的分析我們會發現,TransactionDefinition的主要作用是給出一份事務屬性的定義,然后事務管理器根據給出的定義來創建事務,TransactionStatus主要是用來描述創建后的事務的狀態❞

在對TransactionDefinition跟TransactionStatus有一定了解后,我們再回到PlatformTransactionManager接口本身,PlatformTransactionManager作為事務管理器的基礎接口只是定義管理一個事務必須的三個方法:開啟事務,提交事務,回滾事務,接口僅僅是定義了規范而已,真正做事的還是要依賴它的實現類,所以我們來看看它的繼承關系

PlatformTransactionManager的實現類

PlatformTransactionManager

  •  AbstractPlatformTransactionManager,Spring提供的一個事務管理的基類,提供了事務管理的模板,實現了Spring事務管理的一個標準流程
  1.  判斷當前是否已經存在一個事務
  2.  應用合適的事務傳播行為
  3.  在必要的時候掛起/恢復事務
  4.  提交時檢查事務是否被標記成為rollback-only
  5.  在回滾時做適當的修改(是執行真實的回滾/還是將事務標記成rollback-only)

觸發注冊的同步回調

在AbstractPlatformTransactionManager提供了四個常見的子類,其說明如下

關于事務管理器的詳細代碼分析放到下篇文章,本文對其有個大概了解即可。

Spring中事務的同步機制

Spring中事務相關的同步機制可以分為兩類

  •  資源的同步
  •  行為的同步

什么是資源的同步呢?在一個事務中我們往往會一次執行多個SQL(如果是單條的SQL實際上沒有必要開啟事務),為了保證事務所有的SQL都能夠使用一個數據庫連接,這個時候我們需要將數據庫連接跟事務進行同步,這個時候數據庫連接就是跟這個事務同步的一個資源。

那什么又是行為的同步呢?還是以數據庫連接為例子,在事務開啟之前我們需要先獲取一個數據庫連接,同樣的在事務提交時我們需要將連接關閉(不一定是真正的關閉,如果是連接池只是歸還到連接池中),這個時候關閉連接這個行為也需要跟事務進行同步

那么Spring是如何來管理同步的呢?同樣的,Spring也提供了一個同步管理器TransactionSynchronizationManager,這是一個抽象類,其中所有的方法都是靜態的,并且所有的方法都是圍繞它所申明的幾個靜態常量字段,如下: 

  1. // 這就是同步的資源,Spring就是使用這個完成了連接的同步  
  2. private static final ThreadLocal<Map<Object, Object>> resources =  
  3.     new NamedThreadLocal<>("Transactional resources");  
  4. // TransactionSynchronization完成了行為的同步  
  5. // 關于TransactionSynchronization在后文進行分析  
  6. private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =  
  7.     new NamedThreadLocal<>("Transaction synchronizations"); 
  8. // 事務的名稱  
  9. private static final ThreadLocal<String> currentTransactionName =  
  10.     new NamedThreadLocal<>("Current transaction name");  
  11. // 事務是否被標記成只讀  
  12. private static final ThreadLocal<Boolean> currentTransactionReadOnly =  
  13.     new NamedThreadLocal<>("Current transaction read-only status"); 
  14. // 事物的隔離級別  
  15. private static final ThreadLocal<Integer> currentTransactionIsolationLevel =  
  16.     new NamedThreadLocal<>("Current transaction isolation level");  
  17. // 是否真實開啟了事務   
  18. private static final ThreadLocal<Boolean> actualTransactionActive =  
  19.     new NamedThreadLocal<>("Actual transaction active"); 

可以看到所有的同步都是通過ThreadLocal實現的,對于ThreadLocal本文不做詳細分析,如果對ThreadLocal還不了解的同學也沒有關系,對于本文而言你只需要知道ThreadLocal能將資源跟當前線程綁定即可,例如ThreadLocal<Map<Object, Object>> resources這個屬性就代表要將一個map綁定到當前線程,它提供了set跟get方法,分別用于將屬性綁定到線程上以及獲取線程上綁定的屬性。

上面的幾個變量中除了synchronizations之外其余的應該都很好理解,synchronizations中綁定的是一個TransactionSynchronization的集合,那么這個TransactionSynchronization有什么用呢?我們來看看它的接口定義 

  1. public interface TransactionSynchronization extends Flushable {  
  2.  // 事務完成的狀態  
  3.     // 0 提交  
  4.     // 1 回滾  
  5.     // 2 異常狀態,例如在事務執行時出現異常,然后回滾,回滾時又出現異常  
  6.     // 就會被標記成狀態2  
  7.  int STATUS_COMMITTED = 0 
  8.  int STATUS_ROLLED_BACK = 1 
  9.  int STATUS_UNKNOWN = 2 
  10.     // 我們綁定的這些TransactionSynchronization需要跟事務同步  
  11.     // 1.如果事務掛起,我們需要將其掛起  
  12.     // 2.如果事務恢復,我們需要將其恢復  
  13.  default void suspend() {  
  14.  }  
  15.  default void resume() {  
  16.  }  
  17.  @Override  
  18.  default void flush() {  
  19.  }  
  20.     // 在事務執行過程中,提供的一些回調方法  
  21.  default void beforeCommit(boolean readOnly) {  
  22.  }  
  23.  default void beforeCompletion() {  
  24.  }  
  25.  default void afterCommit() {  
  26.  }  
  27.  default void afterCompletion(int status) {  
  28.  }  

可以看到這個接口就是定義了一些方法,這些個方法可以在事務達到不同階段后執行,可以認為定義了事務執行過程的一些回調行為,這就是我之前說的行為的同步。

模擬Spring事務的實現

本文的最后一部分希望大家模擬一下Spring事務的實現,我們利用現有的AOP來實現事務的管理。數據庫訪問我們直接使用jdbc,在模擬之前我們先明確兩點

  1.  切點應該如何定義?
  2.  通知要實現什么功能?

我們先說第一個問題,因為是我們自己模擬,所以關于切點的定義我們就設置的盡量簡單一些,不妨就直接指定某個包下的所有類。對于第二個問題,我們也不做的過于復雜,在方法執行前開啟事務,在方法執行后提交事務并關閉連接,所以我們需要定義一個環繞通知。同時,我們也需要將連接跟事務同步,保證事務中的所有SQL共用一個事務是實現事務管理的必要條件?;诖?,我們開始編寫代碼

我們只需要引入Spring相關的依賴跟JDBC相關依賴即可,該項目僅僅是一個Spring環境下的Java項目,沒有Web依賴,也不是SpringBoot項目,項目結構如下:

POM文件: 

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"  
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  5.     <modelVersion>4.0.0</modelVersion>  
  6.     <groupId>com.dmz.framework</groupId>  
  7.     <artifactId>mybatis</artifactId>  
  8.     <version>1.0-SNAPSHOT</version> 
  9.     <dependencies>      
  10.         <dependency>  
  11.             <groupId>mysql</groupId>  
  12.             <artifactId>mysql-connector-java</artifactId>  
  13.             <version>8.0.15</version>  
  14.         </dependency>       
  15.          <dependency>  
  16.             <groupId>org.springframework</groupId>  
  17.             <artifactId>spring-context</artifactId>  
  18.             <version>5.2.6.RELEASE</version>  
  19.         </dependency>       
  20.          <dependency>  
  21.             <groupId>org.springframework</groupId>  
  22.             <artifactId>spring-aop</artifactId>  
  23.             <version>5.2.6.RELEASE</version>  
  24.         </dependency> 
  25.         <dependency>  
  26.             <groupId>org.aspectj</groupId>  
  27.             <artifactId>aspectjweaver</artifactId>  
  28.             <version>1.9.5</version>  
  29.         </dependency>  
  30.     </dependencies>  
  31. </project> 

配置類: 

  1. // 開啟AOP跟掃描組件即可  
  2. @EnableAspectJAutoProxy 
  3. @ComponentScan("com.dmz.mybatis.tx_demo")  
  4. public class Config {  

完成事務管理的核心類: 

  1. public class TransactionUtil {  
  2.     public static final ThreadLocal<Connection> synchronousConnection =  
  3.             new ThreadLocal<Connection>();  
  4.     private TransactionUtil() {  
  5.     } 
  6.     public static Connection startTransaction() {  
  7.         Connection connection = synchronousConnection.get();  
  8.         if (connection == null) {  
  9.             try {  
  10.                 // 這里替換成你自己的連接地址即可  
  11.                 connection = DriverManager  
  12.                         .getConnection("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8", "root", "123");  
  13.                 synchronousConnection.set(connection);  
  14.                 connection.setAutoCommit(false);  
  15.             } catch (SQLException e) {  
  16.                 e.printStackTrace();  
  17.             }  
  18.         }  
  19.         return connection;  
  20.     }  
  21.     public static int execute(String sql, Object... args) {  
  22.         Connection connection = startTransaction();  
  23.         try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {  
  24.             if (args != null) {  
  25.                 for (int i = 1; i < args.length + 1; i++) {  
  26.                     preparedStatement.setObject(i, args[i - 1]);  
  27.                 }  
  28.             }  
  29.             return preparedStatement.executeUpdate();  
  30.         } catch (SQLException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         return 0; 
  34.      } 
  35.     public static void commit() {  
  36.         try (Connection connection = synchronousConnection.get()) {  
  37.             connection.commit();  
  38.             synchronousConnection.remove();  
  39.         } catch (SQLException e) {  
  40.             e.printStackTrace();  
  41.         }  
  42.     }  
  43.     public static void rollback() {  
  44.         try (Connection connection = synchronousConnection.get()) {  
  45.             connection.rollback();  
  46.             synchronousConnection.remove();  
  47.         } catch (SQLException e) {  
  48.             e.printStackTrace();  
  49.         }  
  50.     }  

實際需要事務管理的類 

  1. @Component  
  2. public class UserService {  
  3.     public void saveUser() {  
  4.         TransactionUtil.execute  
  5.                 ("INSERT INTO `test`.`user`(`id`, `name`) VALUES (?, ?)", 100, "dmz");  
  6.         // 測試回滾  
  7.         // throw new RuntimeException();  
  8.     }  

切面: 

  1. @Component  
  2. @Aspect  
  3. public class TxAspect {  
  4.     @Pointcut("execution(public * com.dmz.mybatis.tx_demo.service..*.*(..))")  
  5.     private void pointcut() {  
  6.     }  
  7.     @Around("pointcut()") 
  8.      public Object around(JoinPoint joinPoint) throws Throwable {  
  9.         // 在方法執行前開啟事務  
  10.         TransactionUtil.startTransaction();  
  11.         // 執行業務邏輯  
  12.         Object proceed = null 
  13.         try {  
  14.             ProceedingJoinPoint method = (ProceedingJoinPoint) joinPoint;  
  15.             proceed = method.proceed();  
  16.         } catch (Throwable throwable) {  
  17.             // 出現異常進行回滾  
  18.             TransactionUtil.rollback();  
  19.             return proceed;  
  20.         }  
  21.         // 方法執行完成后提交事務  
  22.         TransactionUtil.commit();  
  23.         return proceed;  
  24.     }  

用于測試的主函數: 

  1. public class Main {  
  2.     public static void main(String[] args) {  
  3.         AnnotationConfigApplicationContext ac =  
  4.                 new AnnotationConfigApplicationContext(Config.class);  
  5.         UserService userService = ac.getBean(UserService.class);  
  6.         userService.saveUser();  
  7.     }  

具體的測試過程跟測試結果我就不放了,大家把代碼拷貝過去自行測試就好了

總結

本文主要介紹了Spring中的事務相關內容,對Spring中的事務抽象機制做了介紹,主要是為了讓大家在接下來一篇源碼文章中能減輕負擔,希望大家可以根據自己理解動手模擬下Spring中事務的實現哦,當你自己去實現的時候肯定會碰到一系列的問題,然后帶著這些問題看源碼你才能知道Spring為什么要做這些事情! 

 

責任編輯:龐桂玉 來源: Hollis
相關推薦

2023-10-30 07:36:19

Spring事務傳播機制

2025-01-26 15:38:11

Spring事務編程式

2009-09-25 12:59:53

Hibernate事務

2009-07-20 18:11:52

iBATIS事務Spring

2023-05-05 07:39:04

Spring事務面試

2020-07-17 08:07:54

Spring數據庫事務

2024-12-17 16:44:22

Spring開發

2009-06-22 09:01:57

Spring聲明式事務

2018-11-16 15:35:10

Spring事務Java

2022-08-27 14:14:06

Spring事務開發

2023-12-29 18:53:58

微服務Saga模式

2011-03-25 10:00:23

Spring3.0事務的配置

2024-01-29 08:28:01

Spring事務失效

2022-09-27 21:14:54

Spring事務傳播機制

2025-09-05 07:13:13

2009-06-29 17:54:47

Spring事務隔離

2021-10-29 07:49:22

Spring事務管理

2022-02-14 16:53:57

Spring項目數據庫

2022-08-22 08:04:25

Spring事務Atomicity

2022-04-26 21:49:55

Spring事務數據庫
點贊
收藏

51CTO技術棧公眾號

日本韩国精品一区二区在线观看| 精品不卡在线| 福利91精品一区二区三区| 亚州视频一区二区三区| 日本不卡一区二区三区在线观看| 国产精品乱码妇女bbbb| 丁香花在线电影| 三级性生活视频| 亚洲欧美综合区自拍另类| 综合久久精品| 中文字幕自拍偷拍| 日本一区二区久久精品| 婷婷成人综合网| jazzjazz国产精品久久| 国产一区二区精彩视频| 国产精品69av| 久久综合九色综合欧美98| 好吊日av在线| 国产男女激情视频| 欧美videos大乳护士334| 亚洲精品中文字幕乱码| 亚洲熟妇无码久久精品| 日韩精品资源| 欧美精品第1页| 欧美日韩中字| 日韩免费av网站| 日本不卡久久| 欧美日韩日日摸| 亚洲成人免费| 成人一级免费视频| 无码免费一区二区三区免费播放 | 国产999精品久久久久久| 3344国产永久在线观看视频| 中文字幕一区二区三区人妻不卡| 国产xxx69麻豆国语对白| 中文字幕一区二| 亚洲精品18| 真实的国产乱xxxx在线91| 国产资源第一页| 亚洲天堂一区二区三区| 国产一区二区看久久| 都市激情综合| 久久黄色小视频| 亚洲一区在线直播| 一区二区三区日韩在线| 国产成人免费在线观看| 久久麻豆视频| 无码人妻久久一区二区三区| 黄色一级大片免费| 色播久久人人爽人人爽人人片视av| 国产伦精一区二区三区| 成人开心激情| 九九九在线观看| 国产人妻777人伦精品hd| 精品视频9999| 亚洲欧美色综合| 婷婷中文字幕一区| av在线麻豆| 999在线免费视频| 欧美夜福利tv在线| 精品久久久久久中文字幕| 亚洲精品1234| 欧美xxx网站| 国产成人自拍偷拍| 一区二区成人网| 国产欧美久久久久久| 国产午夜精品一区二区三区嫩草 | 欧美性色aⅴ视频一区日韩精品| 欧美五码在线| 国产精品高潮呻吟AV无码| 国产精品入口免费视| 好吊妞视频这里有精品 | 伊人网在线视频观看| 国产日韩欧美一区二区| 欧美v亚洲v综合ⅴ国产v| 懂色中文一区二区在线播放| 国产欧美自拍一区| 欧美日韩视频精品二区| 色一情一交一乱一区二区三区| 日韩av一区二区三区在线| 日韩一级免费一区| 久久久欧美精品sm网站| 中文在线不卡| 丝袜美腿诱惑一区二区三区| 在线观看日本视频| 亚洲这里只有精品| 91精品在线看| 亚洲国产97在线精品一区| 久久综合狠狠综合久久综合88| 亚洲aaa级| 国产最新在线| 一级黄色大片视频| 丰满少妇一区二区三区| 97中文字幕在线| 91观看网站| 欧美黄色性视频| 欧美mv日韩mv| 亚洲18女电影在线观看| 91在线码无精品| 蜜桃视频一区| 精品成人影院| 日韩美女在线| 日本一级在线观看| 国产午夜福利一区二区| 99热这里只有精品2| 日本一区免费在线观看| 91干在线观看| 亚洲精品久久视频| 午夜精品一区二区三区免费视频| 国产老妇另类xxxxx| 91精品一区国产高清在线gif| 97欧美成人| 黄色免费在线观看| 国产精品亚洲lv粉色| 国产精品丝袜一区二区| 三级黄色片播放| 嫩草影院中文字幕| 国偷自产av一区二区三区小尤奈| 高清欧美一区二区三区 | 日本一级淫片演员| 国产伦理一区二区三区| 136fldh精品导航福利| 国产视频自拍一区| 欧美日韩专区在线| 一区二区三区四区不卡在线| 成人av电影在线网| 久久亚洲图片| 综合五月婷婷| 神马电影久久| 国产精品网址| 自拍偷拍亚洲图片| 亚洲黄色中文字幕| jizz性欧美10| wwwxxx在线观看| 秋霞av鲁丝片一区二区| 国产亚洲久一区二区| 欧美片一区二区| 国产肥白大熟妇bbbb视频| 日本一区二区免费视频| 三上悠亚在线一区| 北条麻妃在线一区| 国产人妻777人伦精品hd| 在线观看成人免费| 日本视频精品一区| 精品国产一区二区三区麻豆免费观看完整版 | 国产日韩视频一区| 性欧美在线视频| xxww在线观看| 999在线免费视频| 国产黄色特级片| 无码精品国产一区二区三区免费| 大陆极品少妇内射aaaaaa| 一区二区三区四区在线视频| 视频一区免费观看| 亚洲精品成人久久久998| 噜噜噜噜噜久久久久久91| 精品亚洲一区二区三区四区五区高| 成人激情av| 99精品国产高清在线观看| 91亚洲精品丁香在线观看| 亚洲一区二区三区xxx视频| 91亚色免费| 国产伦精品一区二区三区在线 | 国产无遮挡免费视频| 久久久精品国产sm调教网站| 波多野结衣亚洲色图| 九九视频在线免费观看| 久久久国产高清| 九九九在线观看| 一区二区视频网站| 国产浮力第一页| 色哟哟国产精品色哟哟| 国产人成在线观看| 最近中文字幕免费mv2018在线| 50度灰在线| 神马电影网我不卡| 九九99久久精品在免费线bt| 国产精品男女| 日韩电影在线视频| 亚洲精品欧美| 久久99国产精品免费网站| 99久久99久久久精品齐齐| 国产精品久久久一本精品| 一区二区三区免费看视频| 亚洲不卡av一区二区三区| 欧美日韩中文字幕精品| 亚洲精品v天堂中文字幕| 视频在线观看99| 国产成人av在线播放| 国产精品免费一区二区三区在线观看 | 国产一区二区三区四区在线| 日韩精品一区三区| 99久久婷婷国产一区二区三区| 香蕉视频黄在线观看| 毛片免费不卡| 日韩一区二区三区四区五区 | 久热精品在线播放| 久久久久亚洲av无码专区桃色| 国产免费无码一区二区视频| 中文字幕第99页| 北条麻妃在线| 久久日本片精品aaaaa国产| 窝窝社区一区二区| 久久国产66| 久久先锋影音av| 日韩欧美在线第一页| 亚洲国产成人av在线| 久久久久国产视频| 国内一区在线| 国产黄视频在线| 亚洲一区二区乱码| www欧美在线| 国产二区视频在线观看| yiren22亚洲综合| 91精品国产福利在线观看麻豆| 韩国av一区二区三区在线观看| 最新国产成人在线观看| 欧美一区二区三区免费在线看 | 精品中国亚洲| 爽爽淫人综合网网站| 中文字幕中文字幕一区二区| 538在线一区二区精品国产| 欧美日韩国产成人在线| 精品国产中文字幕| 在线观看日本一区二区| 国产精品99re| 求av网址在线观看| 色婷婷久久久| 狠狠狠色丁香婷婷综合激情| 午夜欧美在线一二页| 色偷偷88888欧美精品久久久| 亚洲va欧美va国产综合久久| 日韩日韩日韩日韩日韩| 色屁屁草草影院ccyy.com| 日本国产在线观看| 亚洲欧美在线人成swag| 美女爽到呻吟久久久久| 亚洲影院免费观看| 日日狠狠久久偷偷四色综合免费| 国产精品一区二区三区四区五区| 999在线免费视频| 偷偷操不一样的久久| a级片国产精品自在拍在线播放| 女人av一区| av在线不卡电影| 日韩精品在线一区二区| 91久久久久久久久| 国产欧美一区二| 成人午夜精品视频| 桃子视频成人app| 午夜一级在线看亚洲| 天天亚洲美女在线视频| 91高清视频免费| 欧美韩国日本在线| 青青国产在线视频| 国产极品久久久久久久久波多结野| 午夜亚洲伦理| 色综合天天综合在线视频| 欧美最猛性xxxxx免费| 波多野结衣作品集| 亚洲天堂视频在线播放| 久久人体av| 国产aⅴ精品一区二区三区色成熟| 欧美一区三区四区| 成人动漫视频在线观看完整版 | www.xxx麻豆| 天天操天天爽天天干| 欧美成人免费电影| 激情五月播播久久久精品| 精品国产欧美一区二区| 欧美一区免费视频| 欧美极品aaaaabbbbb| 捆绑调教日本一区二区三区| 日韩黄色片在线观看| 欧美日本国产一区| 国产一区二区视频在线免费观看| 粉嫩av蜜桃av蜜臀av| 午夜视频在线看| 日韩视频二区| 欧美一区二区三区性视频| 精品国产免费久久久久久尖叫 | 日韩一区二区免费高清| 欧美高清性xxxxhd| 极品美妇后花庭翘臀娇吟小说| 24小时免费看片在线观看| 久久99精品久久久久久国产越南| 欧美videos大乳护士334| 亚洲高清在线观看一区| 亚洲婷婷综合网| 澳门久久精品| 亚洲男人天堂av网| 国产精品福利在线观看网址| 国产不卡一二三| 亚洲国产精品精华素| 国产一区二区久久| 日韩中文字幕视频| 久久婷婷综合色| 日本三级视频在线播放| 日韩精品亚洲一区| 亚洲第一区第一页| 91在线短视频| 久久视频免费在线观看| 日韩美女毛片| 午夜视频一区二区| 国产一区二区免费电影| 国产精品18p| 日韩高清三区| 欧美日韩在线第一页| 精品国产一区二区三区麻豆免费观看完整版 | 性欧美长视频| 亚洲欧美另类国产| 午夜dv内射一区二区| 国产视频三级在线观看播放| 日本91福利区| 久久99国产综合精品女同| 欧美熟妇另类久久久久久多毛| 在线三级电影| 久久先锋影音av鲁色资源网| 国产美女久久精品| 精品深夜av无码一区二区老年| 亚洲一级大片| 中文字幕精品在线不卡| 成人a免费视频| 亚洲图片在线视频| 国产综合婷婷| 久久成人av网站| 国产又粗又长又黄的视频| 成人国产精品| 中文字幕欧美一| 国产伦精品一区二区三区| 国产婷婷色一区二区在线观看| 成人影视亚洲图片在线| 日韩欧美国产综合| 亚洲 欧美 日韩 国产综合 在线| 性欧美8khd高清极品| 国产精品久久777777毛茸茸| 国产一区二区日韩| 久久久久国产免费| 久久天堂av| 疯狂做受xxxx欧美肥白少妇| 一区二区三区不卡在线| 亚洲色偷精品一区二区三区| 精品一区二区三区日韩| 81精品国产乱码久久久久久| 日本黄色小说视频| 日韩精品影视| 亚洲免费电影在线观看| 亚洲欧美综合视频| 超碰国产精品一区二页| 欧美最新大片在线看| 性高湖久久久久久久久aaaaa| 免费在线观看黄| 国产精品视频线看| 欧美一进一出视频| 久久精品黄色片| 亚欧美无遮挡hd高清在线视频| 亚洲欧洲日产国码av系列天堂| 国产女人18毛片水真多18| av成人综合| 精品91自产拍在线观看一区| 亚洲三级在线视频| 亚洲精品不卡在线观看 | 日韩av高清在线播放| 免费av在线电影| 国产农村妇女毛片精品久久麻豆| 欧美日韩一区二区三区在线视频 | 99re热视频这里只精品| 精品一区日韩成人| 日本中文字幕一区二区有码在线 | 中文字幕 国产| 国产一区二三区| 91最新在线免费观看| 蜜臀av在线观看| 91麻豆精品视频| 水蜜桃一区二区三区| 免费a级在线播放| 亚洲国产成人高清精品| 18岁视频在线观看| 亚洲欧洲日韩精品在线| 亚洲国产成人精品久久| 中文字幕av久久爽一区| 91tv精品福利国产在线观看| 欧美激情一二三| 中文字幕在线视频第一页| 国产成人免费高清| 神马影院我不卡| 91超碰在线播放| 91精品婷婷国产综合久久性色| 亚洲调教欧美在线| 欧美成人日韩| 国产日本欧美一区二区三区| 亚洲精品国产av| 中文字幕在线一区免费| 黄www在线观看| 国产精品17p| 欧美激情亚洲另类| 精品国产伦一区二区三| 国产欧美一区二区三区在线看蜜臀 | 亚洲不卡在线视频| 91麻豆蜜桃一区二区三区|