<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用了這么久的@Transactional,你真的了解嗎?

          共 28940字,需瀏覽 58分鐘

           ·

          2021-04-27 11:22

          點(diǎn)擊上方“程序員大白”,選擇“星標(biāo)”公眾號

          重磅干貨,第一時(shí)間送達(dá)

          來源:juejin.cn/post/6942651630554710046

          數(shù)據(jù)庫的事務(wù)

          數(shù)據(jù)庫事務(wù)(Transaction,簡寫為 TX)是數(shù)據(jù)庫管理系統(tǒng)執(zhí)行過程中的一個(gè)邏輯單位,是可以提交或回滾的工作的原子單元。當(dāng)事務(wù)對數(shù)據(jù)庫進(jìn)行多次更改時(shí),要么在提交事務(wù)時(shí)所有更改都成功,要么在回滾事務(wù)時(shí)所有更改都被撤消。

          數(shù)據(jù)庫(包括但不限于關(guān)系型)事務(wù)一般擁有以下 4 個(gè)特性,稱之為 ACID 特性

          ACID

          • 原子性(Atomicity):事務(wù)作為一個(gè)整體被執(zhí)行,包含在其中的對數(shù)據(jù)庫的操作要么全部被執(zhí)行,要么都不執(zhí)行。
          • 一致性(Consistency):事務(wù)應(yīng)確保數(shù)據(jù)庫的狀態(tài)從一個(gè)一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€(gè)一致狀態(tài)。_一致狀態(tài)_的含義是數(shù)據(jù)庫中的數(shù)據(jù)應(yīng)滿足完整性約束。
          • 隔離性(Isolation):多個(gè)事務(wù)并發(fā)執(zhí)行時(shí),一個(gè)事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行。
          • 持久性(Durability):已被提交的事務(wù)對數(shù)據(jù)庫的修改應(yīng)該永久保存在數(shù)據(jù)庫中。

          Mysql 中的事務(wù)

          START TRANSACTION
              [transaction_characteristic [, transaction_characteristic] ...]

          transaction_characteristic: {
              WITH CONSISTENT SNAPSHOT
            | READ WRITE
            | READ ONLY
          }

          BEGIN [WORK]
          COMMIT [WORK] [AND [NOCHAIN] [[NORELEASE]
          ROLLBACK [WORK] [AND [NOCHAIN] [[NORELEASE]
          SET autocommit = {0 | 1}
          • START TRANSACTION或 BEGIN開始新事務(wù)。
          • COMMIT 提交當(dāng)前事務(wù)。
          • ROLLBACK 回滾當(dāng)前事務(wù)。
          • SET autocommit 禁用或啟用當(dāng)前會(huì)話的默認(rèn)自動(dòng)提交模式。

          默認(rèn)情況下,Mysql 是自動(dòng)提交的模式,所有語句會(huì)立即提交

          JDBC 中的事務(wù)

          JDBC 是 Java 語言中用來規(guī)范客戶端程序如何來訪問數(shù)據(jù)庫的應(yīng)用程序接口,提供了查詢和更新數(shù)據(jù)庫中數(shù)據(jù)的方法。JDBC 也是 Sun Microsystems 的商標(biāo)(現(xiàn)在屬于 Oracle),是面向關(guān)系型數(shù)據(jù)庫的。

          上面說到,Mysql 是默認(rèn)自動(dòng)提交的,所以 JDBC 中事務(wù)事務(wù)的第一步,需要禁用自動(dòng)提交:

          con.setAutoCommit(false);

          提交事務(wù):

          con.commit();

          回滾事務(wù):

          con.rollback();

          一個(gè)完整流程的例子(摘自 Oracle JDBC 文檔):

          public void updateCoffeeSales(HashMap<String, Integer> salesForWeek)
              throws SQLException 
          {

              PreparedStatement updateSales = null;
              PreparedStatement updateTotal = null;

              String updateString =
                  "update " + dbName + ".COFFEES " +
                  "set SALES = ? where COF_NAME = ?";

              String updateStatement =
                  "update " + dbName + ".COFFEES " +
                  "set TOTAL = TOTAL + ? " +
                  "where COF_NAME = ?";

              try {
                  con.setAutoCommit(false);
                  updateSales = con.prepareStatement(updateString);
                  updateTotal = con.prepareStatement(updateStatement);

                  for (Map.Entry<String, Integer> e : salesForWeek.entrySet()) {
                      updateSales.setInt(1, e.getValue().intValue());
                      updateSales.setString(2, e.getKey());
                      updateSales.executeUpdate();
                      updateTotal.setInt(1, e.getValue().intValue());
                      updateTotal.setString(2, e.getKey());
                      updateTotal.executeUpdate();
                      con.commit();
                  }
              } catch (SQLException e ) {
                  JDBCTutorialUtilities.printSQLException(e);
                  if (con != null) {
                      try {
                          System.err.print("Transaction is being rolled back");
                          con.rollback();
                      } catch(SQLException excep) {
                          JDBCTutorialUtilities.printSQLException(excep);
                      }
                  }
              } finally {
                  if (updateSales != null) {
                      updateSales.close();
                  }
                  if (updateTotal != null) {
                      updateTotal.close();
                  }
                  con.setAutoCommit(true);
              }
          }

          為什么需要事務(wù)管理器

          如果沒有事務(wù)管理器的話,我們的程序可能是這樣:

          Connection connection = acquireConnection();
          try{
              int updated = connection.prepareStatement().executeUpdate();
              connection.commit();
          }catch (Exception e){
              rollback(connection);
          }finally {
              releaseConnection(connection);
          }

          也有可能是這樣 "優(yōu)雅的事務(wù)":

          execute(new TxCallback() {
              @Override
              public Object doInTx(Connection var1) {
                  //do something...
                  return null;
              }
          });
          public void execute(TxCallback txCallback){
              Connection connection = acquireConnection();
              try{
                  txCallback.doInTx(connection);
                  connection.commit();
              }catch (Exception e){
                  rollback(connection);
              }finally {
                  releaseConnection(connection);
              }
          }

          # lambda版
          execute(connection -> {
              //do something...
              return null;
          });

          但是以上兩種方式,針對一些復(fù)雜的場景是很不方便的。在實(shí)際的業(yè)務(wù)場景中,往往有比較復(fù)雜的業(yè)務(wù)邏輯,代碼冗長,邏輯關(guān)聯(lián)復(fù)雜,如果一個(gè)大操作中又全是這種代碼的話我想開發(fā)人員可能會(huì)瘋吧。更不用提定制化的隔離級別,以及嵌套 / 獨(dú)立事務(wù)的處理了。

          Spring 事務(wù)管理器(Transaction Manager)簡介

          Spring 作為 Java 最強(qiáng)框架,事務(wù)管理也是其核心功能之一。Spring 為事務(wù)管理提供了統(tǒng)一的抽象,有以下優(yōu)點(diǎn):

          • 跨不同事務(wù) API(例如 Java 事務(wù) API(JTA),JDBC,Hibernate,Java 持久性 API(JPA)和 Java 數(shù)據(jù)對象(JDO))的一致編程模型。
          • 支持聲明式事務(wù)管理(注解形式)
          • 與 JTA 之類的復(fù)雜事務(wù) API 相比, 用于程序化事務(wù)管理的 API 更簡單
          • 和 Spring 的 Data 層抽象集成方便(比如 Spring - Hibernate/Jdbc/Mybatis/Jpa...)

          Spring 的事務(wù)管理器只是一個(gè)接口 / 抽象,不同的 DB 層框架(其實(shí)不光是 DB 類框架,支持事務(wù)模型的理論上都可以使用這套抽象) 可能都需要實(shí)現(xiàn)此標(biāo)準(zhǔn)才可以更好的工作,核心接口是org.springframework.transaction.support.AbstractPlatformTransactionManager,其代碼位于spring-tx模塊中,比如 Hibernate 中的實(shí)現(xiàn)為:org.springframework.orm.hibernate4.HibernateTransactionManager

          使用方式

          事務(wù),自然是控制業(yè)務(wù)的,在一個(gè)業(yè)務(wù)流程內(nèi),往往希望保證原子性,要么全成功要么全失敗。所以事務(wù)一般是加載@Service層,一個(gè) Service 內(nèi)調(diào)用了多個(gè)操作數(shù)據(jù)庫的操作(比如 Dao),在 Service 結(jié)束后事務(wù)自動(dòng)提交,如有異常拋出則事務(wù)回滾。

          這也是 Spring 事務(wù)管理的基本使用原則。

          注解

          在被 Spring 管理的類頭上增加@Transactional注解,即可對該類下的所有方法開啟事務(wù)管理。事務(wù)開啟后,方法內(nèi)的操作無需手動(dòng)開啟 / 提交 / 回滾事務(wù),一切交給 Spring 管理即可。

          @Service
          @Transactional
          public class TxTestService{
              
              @Autowired
              private OrderRepo orderRepo;

              public void submit(Order order){
                  orderRepo.save(order);
              }
          }

          也可以只在方法上配置,方法配置的優(yōu)先級是大于類的

          @Service
          public class TxTestService{
              
              @Autowired
              private OrderRepo orderRepo;


              @Transactional
              public void submit(Order order){
                  orderRepo.save(order);
              }
          }

          TransactionTemplate

          TransactionTemplate 這中方式,其實(shí)和使用注解形式的區(qū)別不大,其核心功能也是由 TransactionManager 實(shí)現(xiàn)的,這里只是換了個(gè)入口

          public <T> execute(TransactionCallback<T> action) throws TransactionException {
              if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
                  return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
              }
              else {
                  //獲取事務(wù)信息
                  TransactionStatus status = this.transactionManager.getTransaction(this);
                  T result;
                  try {
                      //執(zhí)行業(yè)務(wù)代碼
                      result = action.doInTransaction(status);
                  }
                  //處理異?;貪L
                  catch (RuntimeException ex) {
                      // Transactional code threw application exception -> rollback
                      rollbackOnException(status, ex);
                      throw ex;
                  }
                  catch (Error err) {
                      // Transactional code threw error -> rollback
                      rollbackOnException(status, err);
                      throw err;
                  }
                  catch (Exception ex) {
                      // Transactional code threw unexpected exception -> rollback
                      rollbackOnException(status, ex);
                      throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
                  }
                  //提交事務(wù)
                  this.transactionManager.commit(status);
                  return result;
              }
          }

          XML 配置 tx:advice

          過于古老,不做解釋

          隔離級別 (Isolation Level)

          事務(wù)隔離級別是數(shù)據(jù)庫最重要的特性之一,他保證了臟讀 / 幻讀等問題不會(huì)發(fā)生。作為一個(gè)事務(wù)管理框架自然也是支持此配置的,在 @Transactional 注解中有一個(gè) isolation 配置,可以很方便的配置各個(gè)事務(wù)的隔離級別,等同于connection.setTransactionIsolation()

          Isolation {
              DEFAULT(-1),
              READ_UNCOMMITTED(1),
              READ_COMMITTED(2),
              REPEATABLE_READ(4),
              SERIALIZABLE(8);
          }

          傳播行為 (Propagation behavior)

          可能沒有接觸過 Spring 的人聽到傳播行為會(huì)奇怪,這是個(gè)什么東西。

          其實(shí)這個(gè)傳播行為和數(shù)據(jù)庫功能無關(guān),只是事務(wù)管理器為了處理復(fù)雜業(yè)務(wù)而設(shè)計(jì)的一個(gè)機(jī)制。比如現(xiàn)在有這樣一個(gè)調(diào)用場景,A Service -> B Service -> C Service,但是希望 A/B 在一個(gè)事務(wù)內(nèi),C 是一個(gè)獨(dú)立的事務(wù),同時(shí) C 如果出錯(cuò),不影響 AB 所在的事務(wù)。

          此時(shí),就可以通過傳播行為來處理;將 C Service 的事務(wù)配置為@Transactional(propagation = Propagation.REQUIRES_NEW)即可

          Spring 支持以下幾種傳播行為:

          • REQUIRED 默認(rèn)策略,優(yōu)先使用當(dāng)前事務(wù)(及當(dāng)前線程綁定的事務(wù)資源),如果不存在事務(wù),則開啟新事務(wù)
          • SUPPORTS 優(yōu)先使用當(dāng)前的事務(wù)(及當(dāng)前線程綁定的事務(wù)資源),如果不存在事務(wù),則以無事務(wù)方式運(yùn)行
          • MANDATORY 優(yōu)先使用當(dāng)前的事務(wù),如果不存在事務(wù),則拋出異常
          • REQUIRES_NEW 創(chuàng)建一個(gè)新事務(wù),如果存在當(dāng)前事務(wù),則掛起(Suspend)
          • NOT_SUPPORTED 以非事務(wù)方式執(zhí)行,如果當(dāng)前事務(wù)存在,則掛起當(dāng)前事務(wù)。
          • NEVER 以非事務(wù)方式執(zhí)行,如果當(dāng)前事務(wù)存在,則拋出異常

          回滾策略

          @Transactional 中有 4 個(gè)配置回滾策略的屬性,分為 Rollback 策略,和 NoRollback 策略

          默認(rèn)情況下,RuntimeException 和 Error 這兩種異常會(huì)導(dǎo)致事務(wù)回滾,普通的 Exception(需要 Catch 的)異常不會(huì)回滾。

          Rollback

          配置需要回滾的異常類

          # 異常類Class
          Class<? extends Throwable>[] rollbackFor() default {};
          # 異常類ClassName,可以是FullName/SimpleName
          String[] rollbackForClassName() default {};

          NoRollback

          針對一些要特殊處理的業(yè)務(wù)邏輯,比如插一些日志表,或者不重要的業(yè)務(wù)流程,希望就算出錯(cuò)也不影響事務(wù)的提交。(搜索公眾號Java知音,回復(fù)“2021”,送你一份Java面試題寶典)

          可以通過配置 NoRollbackFor 來實(shí)現(xiàn),讓某些異常不影響事務(wù)的狀態(tài)。

          # 異常類Class
          Class<? extends Throwable>[] noRollbackFor() default {};
          # 異常類ClassName,可以是FullName/SimpleName
          String[] noRollbackForClassName() default {};

          只讀控制

          設(shè)置當(dāng)時(shí)事務(wù)的只讀標(biāo)示,等同于connection.setReadOnly()

          關(guān)鍵名詞解釋

          基本原理

          public void execute(TxCallback txCallback){
              //獲取連接
              Connection connection = acquireConnection();
              try{
                  //執(zhí)行業(yè)務(wù)代碼
                  doInService();
                  //提交事務(wù)
                  connection.commit();
              }catch (Exception e){
                  //回滾事務(wù)
                  rollback(connection);
              }finally {
                  //釋放連接
                  releaseConnection(connection);
              }
          }

          Spring 事務(wù)管理的基本原理就是以上代碼,獲取連接 -> 執(zhí)行代碼 -> 提交 / 回滾事務(wù)。Spring 只是將這個(gè)流程給抽象出來了,所有事務(wù)相關(guān)的操作都交由 TransactionManager 去實(shí)現(xiàn),然后封裝一個(gè)模板形式的入口來執(zhí)行 t

          比如org.springframework.transaction.support.TransactionTemplate的實(shí)現(xiàn):

          @Override
              public <T> execute(TransactionCallback<T> action) throws TransactionException {
                  if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
                      return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
                  }
                  else {
                      //通過事務(wù)管理器獲取事務(wù)
                      TransactionStatus status = this.transactionManager.getTransaction(this);
                      T result;
                      try {
                          //執(zhí)行業(yè)務(wù)代碼
                          result = action.doInTransaction(status);
                      }
                      //處理異?;貪L
                      catch (RuntimeException ex) {
                          // Transactional code threw application exception -> rollback
                          rollbackOnException(status, ex);
                          throw ex;
                      }
                      catch (Error err) {
                          // Transactional code threw error -> rollback
                          rollbackOnException(status, err);
                          throw err;
                      }
                      catch (Exception ex) {
                          // Transactional code threw unexpected exception -> rollback
                          rollbackOnException(status, ex);
                          throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
                      }
                      //提交事務(wù)
                      this.transactionManager.commit(status);
                      return result;
                  }
              }

          注解形式的事務(wù)(@Transactional),實(shí)現(xiàn)機(jī)制也是一樣,基于 Spring 的 AOP,將上面 Template 的模式換成了自動(dòng)的 AOP,在 AOP 的 Interceptor(org.springframework.transaction.interceptor.TransactionInterceptor)中來執(zhí)行這套流程:

          protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
                      throws Throwable 
          {

                  // If the transaction attribute is null, the method is non-transactional.
                  final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
                  //獲取事務(wù)管理器
                  final PlatformTransactionManager tm = determineTransactionManager(txAttr);
                  final String joinpointIdentification = methodIdentification(method, targetClass);

                  if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
                      // Standard transaction demarcation with getTransaction and commit/rollback calls.
                      //創(chuàng)建事務(wù)
                      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
                      Object retVal = null;
                      try {
                          // This is an around advice: Invoke the next interceptor in the chain.
                          // This will normally result in a target object being invoked.
                          //執(zhí)行被“AOP”的代碼
                          retVal = invocation.proceedWithInvocation();
                      }
                      catch (Throwable ex) {
                          // target invocation exception
                          //處理異常回滾
                          completeTransactionAfterThrowing(txInfo, ex);
                          throw ex;
                      }
                      finally {
                          //清除資源
                          cleanupTransactionInfo(txInfo);
                      }
                      
                      //提交事務(wù)
                      commitTransactionAfterReturning(txInfo);
                      return retVal;
                  }
             ....
          }

          復(fù)雜流程下的事務(wù)傳播 / 保持相同事務(wù)的關(guān)鍵:

          對于復(fù)雜一些的業(yè)務(wù)流程,會(huì)出現(xiàn)各種類之間的調(diào)用,Spring 是如何做到保持同一個(gè)事務(wù)的?

          其實(shí)基本原理很簡單,只需要將當(dāng)前事務(wù)(Connection)隱式的保存至事務(wù)管理器內(nèi),后續(xù)方法在執(zhí)行 JDBC 操作前,從事務(wù)管理器內(nèi)獲取即可:

          比如HibernateTemplate中的SessionFactory中的getCurrentSession,這里的getCurrentSession就是從(可能是間接的)Spring 事務(wù)管理器中獲取的 Spring 事務(wù)管理器將處理事務(wù)時(shí)的相關(guān)臨時(shí)資源(Connection 等)存在org.springframework.transaction.support.TransactionSynchronizationManager中,通過 ThreadLocal 維護(hù)

          public abstract class TransactionSynchronizationManager {

              private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

              private static final ThreadLocal<Map<Object, Object>> resources =
                      new NamedThreadLocal<Map<Object, Object>>("Transactional resources");

              private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
                      new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");

              private static final ThreadLocal<String> currentTransactionName =
                      new NamedThreadLocal<String>("Current transaction name");

              private static final ThreadLocal<Boolean> currentTransactionReadOnly =
                      new NamedThreadLocal<Boolean>("Current transaction read-only status");

              private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
                      new NamedThreadLocal<Integer>("Current transaction isolation level");

              private static final ThreadLocal<Boolean> actualTransactionActive =
                      new NamedThreadLocal<Boolean>("Actual transaction active");
              ...
          }

          針對一些復(fù)雜場景,嵌套事務(wù) + 獨(dú)立事務(wù),涉及到掛起(suspend),恢復(fù)(resume)的情況,相關(guān)資源也是存儲在TransactionSynchronizationManager 中的,方便嵌套事務(wù)的處理。比如 A->B 時(shí),A 方法已經(jīng)開啟了事務(wù),并將當(dāng)前事務(wù)資源綁定在TransactionSynchronizationManager,那么執(zhí)行 B 之前,會(huì)檢測當(dāng)前是否已經(jīng)存在事務(wù);檢測方式就是從TransactionSynchronizationManager查找并檢測狀態(tài),如果已經(jīng)在事務(wù)內(nèi),那么就根據(jù)不同的傳播行為配置來執(zhí)行不同的邏輯,對于 REQUIRES_NEW 等傳播行為的處理會(huì)麻煩一些,會(huì)涉及到 “掛起(suspend)” 和恢復(fù) (resume) 的操作,原理打通小異,這里就不做過多解釋了

          常見問題

          事務(wù)沒生效

          有下列代碼,入口為 test 方法,在 testTx 方法中配置了 @Transactional 注解,同時(shí)在插入數(shù)據(jù)后拋出 RuntimeException 異常,但是方法執(zhí)行后插入的數(shù)據(jù)并沒有回滾,竟然插入成功了

          public void test(){
              testTx();
          }

          @Transactional
          public void testTx(){
              UrlMappingEntity urlMappingEntity = new UrlMappingEntity();
              urlMappingEntity.setUrl("http://www.baidu.com");
              urlMappingEntity.setExpireIn(777l);
              urlMappingEntity.setCreateTime(new Date());
              urlMappingRepository.save(urlMappingEntity);
              if(true){
                  throw new RuntimeException();
              }
          }

          這里不生效的原因是因?yàn)槿肟诘姆椒?/ 類沒有增加 @Transaction 注解,由于 Spring 的事務(wù)管理器也是基于 AOP 實(shí)現(xiàn)的,不管是 Cglib(ASM) 還是 Jdk 的動(dòng)態(tài)代理,本質(zhì)上也都是子類機(jī)制;在同類之間的方法調(diào)用會(huì)直接調(diào)用本類代碼,不會(huì)執(zhí)行動(dòng)態(tài)代理曾的代碼;所以在這個(gè)例子中,由于入口方法test沒有增加代理注解,所以textTx方法上增加的事務(wù)注解并不會(huì)生效

          異步后事務(wù)失效

          比如在一個(gè)事務(wù)方法中,開啟了子線程操作庫,那么此時(shí)子線程的事務(wù)和主線程事務(wù)是不同的。

          因?yàn)樵?Spring 的事務(wù)管理器中,事務(wù)相關(guān)的資源(連接,session,事務(wù)狀態(tài)之類)都是存放在 TransactionSynchronizationManager 中的,通過 ThreadLocal 存放,如果跨線程的話就無法保證一個(gè)事務(wù)了

          # TransactionSynchronizationManager.java
          private static final ThreadLocal<Map<Object, Object>> resources =
                  new NamedThreadLocal<>("Transactional resources");
          private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
                  new NamedThreadLocal<>("Transaction synchronizations");
          private static final ThreadLocal<String> currentTransactionName =
                  new NamedThreadLocal<>("Current transaction name");
          private static final ThreadLocal<Boolean> currentTransactionReadOnly =
                  new NamedThreadLocal<>("Current transaction read-only status");
          private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
                  new NamedThreadLocal<>("Current transaction isolation level");
          private static final ThreadLocal<Boolean> actualTransactionActive =
                  new NamedThreadLocal<>("Actual transaction active");

          事務(wù)提交失敗

          org.springframework.transaction.UnexpectedRollbackException: 
          Transaction silently rolled back because it has been marked as rollback-only

          這個(gè)異常是由于在同一個(gè)事務(wù)內(nèi),多個(gè)事務(wù)方法之間調(diào)用,子方法拋出異常,但又被父方法忽略了導(dǎo)致的。

          因?yàn)樽臃椒⊕伋隽水惓#琒pring 事務(wù)管理器會(huì)將當(dāng)前事務(wù)標(biāo)為失敗狀態(tài),準(zhǔn)備進(jìn)行回滾,可是當(dāng)子方法執(zhí)行完畢出棧后,父方法又忽略了此異常,待方法執(zhí)行完畢后正常提交時(shí),事務(wù)管理器會(huì)檢查回滾狀態(tài),若有回滾標(biāo)示則拋出此異常。

          具體可以參考org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

          示例代碼:

          A -> B
          # A Service(@Transactional):
          public void testTx(){
              urlMappingRepo.deleteById(98l);
              try{
                  txSubService.testSubTx();
              }catch (Exception e){
                  e.printStackTrace();
              }
          }

          # B Service(@Transactional)
          public void testSubTx(){
              if(true){
                  throw new RuntimeException();
              }
          }

          參考

          • https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
          • https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html
          • https://www.cnblogs.com/micrari/p/7612962.html


          國產(chǎn)小眾瀏覽器因屏蔽視頻廣告,被索賠100萬(后續(xù))

          年輕人“不講武德”:因看黃片上癮,把網(wǎng)站和786名女主播起訴了

          中國聯(lián)通官網(wǎng)被發(fā)現(xiàn)含木馬腳本,可向用戶推廣色情APP

          張一鳴:每個(gè)逆襲的年輕人,都具備的底層能力


          關(guān)


          ,學(xué),西學(xué)學(xué)運(yùn)護(hù)質(zhì),結(jié),關(guān)[],學(xué)習(xí)進(jìn)!


          瀏覽 93
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91人妻人人澡人人爽精品 | 久久色成人电影 | 亚洲色图欧美日韩 | 欧美中文字幕在线 | 色欲网址 |