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

聊聊Spring事務(wù)失效的12種場景,太坑了

開發(fā) 架構(gòu)
在某些業(yè)務(wù)場景下,如果一個請求中,需要同時寫入多張表的數(shù)據(jù)。為了保證操作的原子性(要么同時成功,要么同時失敗),避免數(shù)據(jù)不一致的情況,我們一般都會用到spring事務(wù)。

[[421644]]

前言

對于從事java開發(fā)工作的同學(xué)來說,spring的事務(wù)肯定再熟悉不過了。

在某些業(yè)務(wù)場景下,如果一個請求中,需要同時寫入多張表的數(shù)據(jù)。為了保證操作的原子性(要么同時成功,要么同時失敗),避免數(shù)據(jù)不一致的情況,我們一般都會用到spring事務(wù)。

確實,spring事務(wù)用起來賊爽,就用一個簡單的注解:@Transactional,就能輕松搞定事務(wù)。我猜大部分小伙伴也是這樣用的,而且一直用一直爽。

但如果你使用不當,它也會坑你于無形。

今天我們就一起聊聊,事務(wù)失效的一些場景,說不定你已經(jīng)中招了。不信,讓我們一起看看。

一 事務(wù)不生效

1.訪問權(quán)限問題

眾所周知,java的訪問權(quán)限主要有四種:private、default、protected、public,它們的權(quán)限從左到右,依次變大。

但如果我們在開發(fā)過程中,把有某些事務(wù)方法,定義了錯誤的訪問權(quán)限,就會導(dǎo)致事務(wù)功能出問題,例如:

  1. @Service 
  2. public class UserService { 
  3.      
  4.     @Transactional 
  5.     private void add(UserModel userModel) { 
  6.          saveData(userModel); 
  7.          updateData(userModel); 
  8.     } 

我們可以看到add方法的訪問權(quán)限被定義成了private,這樣會導(dǎo)致事務(wù)失效,spring要求被代理方法必須是public的。

說白了,在AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法中有個判斷,如果目標方法不是public,則TransactionAttribute返回null,即不支持事務(wù)。

  1. protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { 
  2.     // Don't allow no-public methods as required. 
  3.     if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { 
  4.       return null
  5.     } 
  6.  
  7.     // The method may be on an interface, but we need attributes from the target class. 
  8.     // If the target class is null, the method will be unchanged. 
  9.     Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); 
  10.  
  11.     // First try is the method in the target class. 
  12.     TransactionAttribute txAttr = findTransactionAttribute(specificMethod); 
  13.     if (txAttr != null) { 
  14.       return txAttr; 
  15.     } 
  16.  
  17.     // Second try is the transaction attribute on the target class. 
  18.     txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); 
  19.     if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { 
  20.       return txAttr; 
  21.     } 
  22.  
  23.     if (specificMethod != method) { 
  24.       // Fallback is to look at the original method. 
  25.       txAttr = findTransactionAttribute(method); 
  26.       if (txAttr != null) { 
  27.         return txAttr; 
  28.       } 
  29.       // Last fallback is the class of the original method. 
  30.       txAttr = findTransactionAttribute(method.getDeclaringClass()); 
  31.       if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { 
  32.         return txAttr; 
  33.       } 
  34.     } 
  35.     return null
  36.   } 

也就是說,如果我們自定義的事務(wù)方法(即目標方法),它的訪問權(quán)限不是public,而是private、default或protected的話,spring則不會提供事務(wù)功能。

2. 方法用final修飾

有時候,某個方法不想被子類重新,這時可以將該方法定義成final的。普通方法這樣定義是沒問題的,但如果將事務(wù)方法定義成final,例如:

  1. @Service 
  2. public class UserService { 
  3.  
  4.     @Transactional 
  5.     public final void add(UserModel userModel){ 
  6.         saveData(userModel); 
  7.         updateData(userModel); 
  8.     } 

我們可以看到add方法被定義成了final的,這樣會導(dǎo)致事務(wù)失效。

為什么?

如果你看過spring事務(wù)的源碼,可能會知道spring事務(wù)底層使用了aop,也就是通過jdk動態(tài)代理或者cglib,幫我們生成了代理類,在代理類中實現(xiàn)的事務(wù)功能。

但如果某個方法用final修飾了,那么在它的代理類中,就無法重寫該方法,而添加事務(wù)功能。

注意:如果某個方法是static的,同樣無法通過動態(tài)代理,變成事務(wù)方法。

3.方法內(nèi)部調(diào)用

有時候我們需要在某個Service類的某個方法中,調(diào)用另外一個事務(wù)方法,比如:

  1. @Service 
  2. public class UserService { 
  3.  
  4.     @Autowired 
  5.     private UserMapper userMapper; 
  6.  
  7.     @Transactional 
  8.     public void add(UserModel userModel) { 
  9.         userMapper.insertUser(userModel); 
  10.         updateStatus(userModel); 
  11.     } 
  12.  
  13.     @Transactional 
  14.     public void updateStatus(UserModel userModel) { 
  15.         doSameThing(); 
  16.     } 

我們看到在事務(wù)方法add中,直接調(diào)用事務(wù)方法updateStatus。從前面介紹的內(nèi)容可以知道,updateStatus方法擁有事務(wù)的能力是因為spring aop生成代理了對象,但是這種方法直接調(diào)用了this對象的方法,所以updateStatus方法不會生成事務(wù)。

由此可見,在同一個類中的方法直接內(nèi)部調(diào)用,會導(dǎo)致事務(wù)失效。

那么問題來了,如果有些場景,確實想在同一個類的某個方法中,調(diào)用它自己的另外一個方法,該怎么辦呢?

3.1 新加一個Service方法

這個方法非常簡單,只需要新加一個Service方法,把@Transactional注解加到新Service方法上,把需要事務(wù)執(zhí)行的代碼移到新方法中。具體代碼如下:

  1. @Servcie 
  2. public class ServiceA { 
  3.    @Autowired 
  4.    prvate ServiceB serviceB; 
  5.  
  6.    public void save(User user) { 
  7.          queryData1(); 
  8.          queryData2(); 
  9.          serviceB.doSave(user); 
  10.    } 
  11.  } 
  12.  
  13.  @Servcie 
  14.  public class ServiceB { 
  15.  
  16.     @Transactional(rollbackFor=Exception.class) 
  17.     public void doSave(User user) { 
  18.        addData1(); 
  19.        updateData2(); 
  20.     } 
  21.  
  22.  } 

3.2 在該Service類中注入自己

如果不想再新加一個Service類,在該Service類中注入自己也是一種選擇。具體代碼如下:

  1. @Servcie 
  2. public class ServiceA { 
  3.    @Autowired 
  4.    prvate ServiceA serviceA; 
  5.  
  6.    public void save(User user) { 
  7.          queryData1(); 
  8.          queryData2(); 
  9.          serviceA.doSave(user); 
  10.    } 
  11.  
  12.    @Transactional(rollbackFor=Exception.class) 
  13.    public void doSave(User user) { 
  14.        addData1(); 
  15.        updateData2(); 
  16.     } 
  17.  } 

可能有些人可能會有這樣的疑問:這種做法會不會出現(xiàn)循環(huán)依賴問題?

答案:不會。

其實spring ioc內(nèi)部的三級緩存保證了它,不會出現(xiàn)循環(huán)依賴問題。但有些坑,如果你想進一步了解循環(huán)依賴問題,可以看看我之前文章《spring:我是如何解決循環(huán)依賴的?》。

3.3 通過AopContent類

在該Service類中使用AopContext.currentProxy()獲取代理對象

上面的方法2確實可以解決問題,但是代碼看起來并不直觀,還可以通過在該Service類中使用AOPProxy獲取代理對象,實現(xiàn)相同的功能。具體代碼如下:

  1. @Servcie 
  2. public class ServiceA { 
  3.  
  4.    public void save(User user) { 
  5.          queryData1(); 
  6.          queryData2(); 
  7.          ((ServiceA)AopContext.currentProxy()).doSave(user); 
  8.    } 
  9.  
  10.    @Transactional(rollbackFor=Exception.class) 
  11.    public void doSave(User user) { 
  12.        addData1(); 
  13.        updateData2(); 
  14.     } 
  15.  } 

4.未被spring管理

在我們平時開發(fā)過程中,有個細節(jié)很容易被忽略。即使用spring事務(wù)的前提是:對象要被spring管理,需要創(chuàng)建bean實例。

通常情況下,我們通過@Controller、@Service、@Component、@Repository等注解,可以自動實現(xiàn)bean實例化和依賴注入的功能。

當然創(chuàng)建bean實例的方法還有很多,有興趣的小伙伴可以看看我之前寫的另一篇文章《@Autowired的這些騷操作,你都知道嗎?》

如果有一天,你匆匆忙忙的開發(fā)了一個Service類,但忘了加@Service注解,比如:

  1. //@Service 
  2. public class UserService { 
  3.  
  4.     @Transactional 
  5.     public void add(UserModel userModel) { 
  6.          saveData(userModel); 
  7.          updateData(userModel); 
  8.     }     

從上面的例子,我們可以看到UserService類沒有加@Service注解,那么該類不會交給spring管理,所以它的add方法也不會生成事務(wù)。

5.多線程調(diào)用

在實際項目開發(fā)中,多線程的使用場景還是挺多的。如果spring事務(wù)用在多線程場景中,會有問題嗎?

  1. @Slf4j 
  2. @Service 
  3. public class UserService { 
  4.  
  5.     @Autowired 
  6.     private UserMapper userMapper; 
  7.     @Autowired 
  8.     private RoleService roleService; 
  9.  
  10.     @Transactional 
  11.     public void add(UserModel userModel) throws Exception { 
  12.         userMapper.insertUser(userModel); 
  13.         new Thread(() -> { 
  14.             roleService.doOtherThing(); 
  15.         }).start(); 
  16.     } 
  17.  
  18. @Service 
  19. public class RoleService { 
  20.  
  21.     @Transactional 
  22.     public void doOtherThing() { 
  23.         System.out.println("保存role表數(shù)據(jù)"); 
  24.     } 

從上面的例子中,我們可以看到事務(wù)方法add中,調(diào)用了事務(wù)方法doOtherThing,但是事務(wù)方法doOtherThing是在另外一個線程中調(diào)用的。

這樣會導(dǎo)致兩個方法不在同一個線程中,獲取到的數(shù)據(jù)庫連接不一樣,從而是兩個不同的事務(wù)。如果想doOtherThing方法中拋了異常,add方法也回滾是不可能的。

如果看過spring事務(wù)源碼的朋友,可能會知道spring的事務(wù)是通過數(shù)據(jù)庫連接來實現(xiàn)的。當前線程中保存了一個map,key是數(shù)據(jù)源,value是數(shù)據(jù)庫連接。

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

我們說的同一個事務(wù),其實是指同一個數(shù)據(jù)庫連接,只有擁有同一個數(shù)據(jù)庫連接才能同時提交和回滾。如果在不同的線程,拿到的數(shù)據(jù)庫連接肯定是不一樣的,所以是不同的事務(wù)。

6.表不支持事務(wù)

周所周知,在mysql5之前,默認的數(shù)據(jù)庫引擎是myisam。

它的好處就不用多說了:索引文件和數(shù)據(jù)文件是分開存儲的,對于查多寫少的單表操作,性能比innodb更好。

有些老項目中,可能還在用它。

在創(chuàng)建表的時候,只需要把ENGINE參數(shù)設(shè)置成MyISAM即可:

  1. CREATE TABLE `category` ( 
  2.   `id` bigint NOT NULL AUTO_INCREMENT, 
  3.   `one_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL
  4.   `two_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL
  5.   `three_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL
  6.   `four_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL
  7.   PRIMARY KEY (`id`) 
  8. ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin 

myisam好用,但有個很致命的問題是:不支持事務(wù)。

如果只是單表操作還好,不會出現(xiàn)太大的問題。但如果需要跨多張表操作,由于其不支持事務(wù),數(shù)據(jù)極有可能會出現(xiàn)不完整的情況。

此外,myisam還不支持行鎖和外鍵。

所以在實際業(yè)務(wù)場景中,myisam使用的并不多。在mysql5以后,myisam已經(jīng)逐漸退出了歷史的舞臺,取而代之的是innodb。

有時候我們在開發(fā)的過程中,發(fā)現(xiàn)某張表的事務(wù)一直都沒有生效,那不一定是spring事務(wù)的鍋,最好確認一下你使用的那張表,是否支持事務(wù)。

7.未開啟事務(wù)

有時候,事務(wù)沒有生效的根本原因是沒有開啟事務(wù)。

你看到這句話可能會覺得好笑。

開啟事務(wù)不是一個項目中,最最最基本的功能嗎?

為什么還會沒有開啟事務(wù)?

沒錯,如果項目已經(jīng)搭建好了,事務(wù)功能肯定是有的。

但如果你是在搭建項目demo的時候,只有一張表,而這張表的事務(wù)沒有生效。那么會是什么原因造成的呢?

當然原因有很多,但沒有開啟事務(wù),這個原因極其容易被忽略。

如果你使用的是springboot項目,那么你很幸運。因為springboot通過DataSourceTransactionManagerAutoConfiguration類,已經(jīng)默默的幫你開啟了事務(wù)。

你所要做的事情很簡單,只需要配置spring.datasource相關(guān)參數(shù)即可。

但如果你使用的還是傳統(tǒng)的spring項目,則需要在applicationContext.xml文件中,手動配置事務(wù)相關(guān)參數(shù)。如果忘了配置,事務(wù)肯定是不會生效的。

具體配置如下信息:

  1.     
  2. <!-- 配置事務(wù)管理器 -->  
  3. <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">  
  4.     <property name="dataSource" ref="dataSource"></property>  
  5. </bean>  
  6. <tx:advice id="advice" transaction-manager="transactionManager">  
  7.     <tx:attributes>  
  8.         <tx:method name="*" propagation="REQUIRED"/> 
  9.     </tx:attributes>  
  10. </tx:advice>  
  11. <!-- 用切點把事務(wù)切進去 -->  
  12. <aop:config>  
  13.     <aop:pointcut expression="execution(* com.susan.*.*(..))" id="pointcut"/>  
  14.     <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>  
  15. </aop:config>  

 

 

 

 

默默的說一句,如果在pointcut標簽中的切入點匹配規(guī)則,配錯了的話,有些類的事務(wù)也不會生效。

二 事務(wù)不回滾

1.錯誤的傳播特性

其實,我們在使用@Transactional注解時,是可以指定propagation參數(shù)的。

該參數(shù)的作用是指定事務(wù)的傳播特性,spring目前支持7種傳播特性:

  • REQUIRED 如果當前上下文中存在事務(wù),那么加入該事務(wù),如果不存在事務(wù),創(chuàng)建一個事務(wù),這是默認的傳播屬性值。
  • SUPPORTS 如果當前上下文存在事務(wù),則支持事務(wù)加入事務(wù),如果不存在事務(wù),則使用非事務(wù)的方式執(zhí)行。
  • MANDATORY 如果當前上下文中存在事務(wù),否則拋出異常。
  • REQUIRES_NEW 每次都會新建一個事務(wù),并且同時將上下文中的事務(wù)掛起,執(zhí)行當前新建事務(wù)完成以后,上下文事務(wù)恢復(fù)再執(zhí)行。
  • NOT_SUPPORTED 如果當前上下文中存在事務(wù),則掛起當前事務(wù),然后新的方法在沒有事務(wù)的環(huán)境中執(zhí)行。
  • NEVER 如果當前上下文中存在事務(wù),則拋出異常,否則在無事務(wù)環(huán)境上執(zhí)行代碼。
  • NESTED 如果當前上下文中存在事務(wù),則嵌套事務(wù)執(zhí)行,如果不存在事務(wù),則新建事務(wù)。

如果我們在手動設(shè)置propagation參數(shù)的時候,把傳播特性設(shè)置錯了,比如:

  1. @Service 
  2. public class UserService { 
  3.  
  4.     @Transactional(propagation = Propagation.NEVER) 
  5.     public void add(UserModel userModel) { 
  6.         saveData(userModel); 
  7.         updateData(userModel); 
  8.     } 

我們可以看到add方法的事務(wù)傳播特性定義成了Propagation.NEVER,這種類型的傳播特性不支持事務(wù),如果有事務(wù)則會拋異常。

目前只有這三種傳播特性才會創(chuàng)建新事務(wù):REQUIRED,REQUIRES_NEW,NESTED。

2.自己吞了異常

事務(wù)不會回滾,最常見的問題是:開發(fā)者在代碼中手動try...catch了異常。比如:

  1. @Slf4j 
  2. @Service 
  3. public class UserService { 
  4.      
  5.     @Transactional 
  6.     public void add(UserModel userModel) { 
  7.         try { 
  8.             saveData(userModel); 
  9.             updateData(userModel); 
  10.         } catch (Exception e) { 
  11.             log.error(e.getMessage(), e); 
  12.         } 
  13.     } 

這種情況下spring事務(wù)當然不會回滾,因為開發(fā)者自己捕獲了異常,又沒有手動拋出,換句話說就是把異常吞掉了。

如果想要spring事務(wù)能夠正常回滾,必須拋出它能夠處理的異常。如果沒有拋異常,則spring認為程序是正常的。

3.手動拋了別的異常

即使開發(fā)者沒有手動捕獲異常,但如果拋的異常不正確,spring事務(wù)也不會回滾。

  1. @Slf4j 
  2. @Service 
  3. public class UserService { 
  4.      
  5.     @Transactional 
  6.     public void add(UserModel userModel) throws Exception { 
  7.         try { 
  8.              saveData(userModel); 
  9.              updateData(userModel); 
  10.         } catch (Exception e) { 
  11.             log.error(e.getMessage(), e); 
  12.             throw new Exception(e); 
  13.         } 
  14.     } 

上面的這種情況,開發(fā)人員自己捕獲了異常,又手動拋出了異常:Exception,事務(wù)同樣不會回滾。

因為spring事務(wù),默認情況下只會回滾RuntimeException(運行時異常)和Error(錯誤),對于普通的Exception(非運行時異常),它不會回滾。

4.自定義了回滾異常

在使用@Transactional注解聲明事務(wù)時,有時我們想自定義回滾的異常,spring也是支持的。可以通過設(shè)置rollbackFor參數(shù),來完成這個功能。

但如果這個參數(shù)的值設(shè)置錯了,就會引出一些莫名其妙的問題,例如:

  1. @Slf4j 
  2. @Service 
  3. public class UserService { 
  4.      
  5.     @Transactional(rollbackFor = BusinessException.class) 
  6.     public void add(UserModel userModel) throws Exception { 
  7.        saveData(userModel); 
  8.        updateData(userModel); 
  9.     } 

如果在執(zhí)行上面這段代碼,保存和更新數(shù)據(jù)時,程序報錯了,拋了SqlException、DuplicateKeyException等異常。而BusinessException是我們自定義的異常,報錯的異常不屬于BusinessException,所以事務(wù)也不會回滾。

即使rollbackFor有默認值,但阿里巴巴開發(fā)者規(guī)范中,還是要求開發(fā)者重新指定該參數(shù)。

這是為什么呢?

因為如果使用默認值,一旦程序拋出了Exception,事務(wù)不會回滾,這會出現(xiàn)很大的bug。所以,建議一般情況下,將該參數(shù)設(shè)置成:Exception或Throwable。

5.嵌套事務(wù)回滾多了

  1. public class UserService { 
  2.  
  3.     @Autowired 
  4.     private UserMapper userMapper; 
  5.  
  6.     @Autowired 
  7.     private RoleService roleService; 
  8.  
  9.     @Transactional 
  10.     public void add(UserModel userModel) throws Exception { 
  11.         userMapper.insertUser(userModel); 
  12.         roleService.doOtherThing(); 
  13.     } 
  14.  
  15. @Service 
  16. public class RoleService { 
  17.  
  18.     @Transactional(propagation = Propagation.NESTED) 
  19.     public void doOtherThing() { 
  20.         System.out.println("保存role表數(shù)據(jù)"); 
  21.     } 

這種情況使用了嵌套的內(nèi)部事務(wù),原本是希望調(diào)用roleService.doOtherThing方法時,如果出現(xiàn)了異常,只回滾doOtherThing方法里的內(nèi)容,不回滾 userMapper.insertUser里的內(nèi)容,即回滾保存點。。但事實是,insertUser也回滾了。

why?

因為doOtherThing方法出現(xiàn)了異常,沒有手動捕獲,會繼續(xù)往上拋,到外層add方法的代理方法中捕獲了異常。所以,這種情況是直接回滾了整個事務(wù),不只回滾單個保存點。

怎么樣才能只回滾保存點呢?

  1. @Slf4j 
  2. @Service 
  3. public class UserService { 
  4.  
  5.     @Autowired 
  6.     private UserMapper userMapper; 
  7.  
  8.     @Autowired 
  9.     private RoleService roleService; 
  10.  
  11.     @Transactional 
  12.     public void add(UserModel userModel) throws Exception { 
  13.  
  14.         userMapper.insertUser(userModel); 
  15.         try { 
  16.             roleService.doOtherThing(); 
  17.         } catch (Exception e) { 
  18.             log.error(e.getMessage(), e); 
  19.         } 
  20.     } 

可以將內(nèi)部嵌套事務(wù)放在try/catch中,并且不繼續(xù)往上拋異常。這樣就能保證,如果內(nèi)部嵌套事務(wù)中出現(xiàn)異常,只回滾內(nèi)部事務(wù),而不影響外部事務(wù)。

三 其他

1 大事務(wù)問題

在使用spring事務(wù)時,有個讓人非常頭疼的問題,就是大事務(wù)問題。

通常情況下,我們會在方法上@Transactional注解,填加事務(wù)功能,比如:

  1. @Service 
  2. public class UserService { 
  3.      
  4.     @Autowired  
  5.     private RoleService roleService; 
  6.      
  7.     @Transactional 
  8.     public void add(UserModel userModel) throws Exception { 
  9.        query1(); 
  10.        query2(); 
  11.        query3(); 
  12.        roleService.save(userModel); 
  13.        update(userModel); 
  14.     } 
  15.  
  16.  
  17. @Service 
  18. public class RoleService { 
  19.      
  20.     @Autowired  
  21.     private RoleService roleService; 
  22.      
  23.     @Transactional 
  24.     public void save(UserModel userModel) throws Exception { 
  25.        query4(); 
  26.        query5(); 
  27.        query6(); 
  28.        saveData(userModel); 
  29.     } 

但@Transactional注解,如果被加到方法上,有個缺點就是整個方法都包含在事務(wù)當中了。

上面的這個例子中,在UserService類中,其實只有這兩行才需要事務(wù):

  1. roleService.save(userModel); 
  2. update(userModel); 

在RoleService類中,只有這一行需要事務(wù):

  1. saveData(userModel); 

現(xiàn)在的這種寫法,會導(dǎo)致所有的query方法也被包含在同一個事務(wù)當中。

如果query方法非常多,調(diào)用層級很深,而且有部分查詢方法比較耗時的話,會造成整個事務(wù)非常耗時,而從造成大事務(wù)問題。

關(guān)于大事務(wù)問題的危害,可以閱讀一下我的另一篇文章《讓人頭痛的大事務(wù)問題到底要如何解決?》,上面有詳細的講解。

2.編程式事務(wù)

上面聊的這些內(nèi)容都是基于@Transactional注解的,主要說的是它的事務(wù)問題,我們把這種事務(wù)叫做:聲明式事務(wù)。

其實,spring還提供了另外一種創(chuàng)建事務(wù)的方式,即通過手動編寫代碼實現(xiàn)的事務(wù),我們把這種事務(wù)叫做:編程式事務(wù)。例如:

  1. @Autowired 
  2. private TransactionTemplate transactionTemplate; 
  3.  
  4. ... 
  5.  
  6. public void save(final User user) { 
  7.       queryData1(); 
  8.       queryData2(); 
  9.       transactionTemplate.execute((status) => { 
  10.          addData1(); 
  11.          updateData2(); 
  12.          return Boolean.TRUE
  13.       }) 

在spring中為了支持編程式事務(wù),專門提供了一個類:TransactionTemplate,在它的execute方法中,就實現(xiàn)了事務(wù)的功能。

相較于@Transactional注解聲明式事務(wù),我更建議大家使用,基于TransactionTemplate的編程式事務(wù)。主要原因如下:

  • 避免由于spring aop問題,導(dǎo)致事務(wù)失效的問題。
  • 能夠更小粒度的控制事務(wù)的范圍,更直觀。

 

建議在項目中少使用@Transactional注解開啟事務(wù)。但并不是說一定不能用它,如果項目中有些業(yè)務(wù)邏輯比較簡單,而且不經(jīng)常變動,使用@Transactional注解開啟事務(wù)開啟事務(wù)也無妨,因為它更簡單,開發(fā)效率更高,但是千萬要小心事務(wù)失效的問題。

 

責(zé)任編輯:武曉燕 來源: 蘇三說技術(shù)
相關(guān)推薦

2022-01-09 18:32:03

MySQL SQL 語句數(shù)據(jù)庫

2024-09-09 08:29:25

2022-08-09 09:34:32

Spring開發(fā)

2022-08-08 17:38:45

Spring策略事務(wù)

2022-02-14 16:53:57

Spring項目數(shù)據(jù)庫

2022-05-02 21:47:13

并發(fā)編程線程

2023-07-05 08:45:18

Spring事務(wù)失效場景

2022-05-26 08:23:05

MySQL索引數(shù)據(jù)庫

2022-12-06 10:39:43

Spring事務(wù)失效

2022-07-05 14:19:30

Spring接口CGLIB

2024-01-29 08:28:01

Spring事務(wù)失效

2021-12-13 11:12:41

Spring事務(wù)失效

2025-10-30 07:45:06

2022-10-11 11:38:23

Spring

2021-04-14 15:17:08

Transaction代碼語言

2022-02-28 08:55:31

數(shù)據(jù)庫MySQL索引

2025-02-10 00:27:54

2024-05-07 08:23:03

Spring@Async配置

2023-05-26 07:19:49

Spring聲明式事務(wù)

2023-09-28 09:07:54

注解失效場景
點贊
收藏

51CTO技術(shù)棧公眾號

亚洲清纯自拍| 免费看成人人体视频| 亚洲欧美另类久久久精品2019| 97人人做人人人难人人做| 亚洲国产精品午夜在线观看| 久久91麻豆精品一区| 91麻豆精品国产91久久久使用方法| 99在线观看视频免费| 国产高清在线观看| 国产成人精品免费看| 国产精品久久久久久一区二区| 欧美精品久久久久久久久46p| 爽爽窝窝午夜精品一区二区| 91精品国产综合久久福利软件 | wwwww在线观看免费视频| 国产成人免费视频一区| 国产mv免费观看入口亚洲| 欧美日韩在线视频免费| 精品国产一区二区三区av片| 亚洲国产成人久久综合一区| 超碰中文字幕在线观看| japanese23hdxxxx日韩| 精品国产乱码久久久久久虫虫漫画 | 五月婷婷丁香六月| 国产麻豆精品一区二区| 国产精品美女呻吟| 无码人妻精品一区二区50| 亚洲免费激情| 欧美精品videofree1080p| www.99re6| 日韩国产综合| 在线视频中文亚洲| 免费污网站在线观看| 噜噜噜狠狠夜夜躁精品仙踪林| 欧美一区三区四区| 亚洲小视频网站| 五月激情久久| 一本色道**综合亚洲精品蜜桃冫| 男人天堂手机在线视频| 天堂8中文在线| 亚洲精品成人少妇| 国产免费一区二区三区四在线播放| 永久免费av在线| 国产精品免费网站在线观看| 日韩精品欧美在线| 国产高清在线看| 国产精品天干天干在线综合| 日韩一区国产在线观看| 国产福利电影在线| 中文字幕av一区二区三区高 | 午夜精品一区| 欧美极品少妇xxxxⅹ高跟鞋 | 波多野结衣久草一区| 国产女人高潮时对白| 国产精品综合av一区二区国产馆| 成人国产精品一区| 国产三级第一页| 国产高清不卡一区| 国产精品大全| 日韩大片b站免费观看直播| 91蝌蚪porny| 日韩欧美三级电影| 欧美激情办公室videoshd| 亚洲日本在线视频观看| 波多野结衣与黑人| 极品视频在线| 欧美日韩综合一区| 超碰在线免费av| 国产精品一区二区三区美女| 精品香蕉一区二区三区| 国产传媒在线看| 亚洲精品国产成人影院| 久久免费国产视频| 国产精品久免费的黄网站| 日本网站在线观看一区二区三区| 成人黄色免费网站在线观看| 亚洲国产中文字幕在线| 久久久www成人免费毛片麻豆| 色涩成人影视在线播放| 婷婷丁香在线| 一本色道综合亚洲| 成人高清在线观看视频| 日韩最新在线| 久久久精品免费视频| 久久草视频在线| 免播放器亚洲一区| 国产欧美一区二区三区另类精品| 男男电影完整版在线观看| 中文字幕在线免费不卡| 2018日日夜夜| 国产精品伦一区二区| 精品国产第一区二区三区观看体验| 青青草成人免费视频| 成人精品视频| 久久青草福利网站| 中文字幕 日韩有码| 国产精品一区专区| 日韩国产精品一区二区| 欧洲日本在线| 日韩欧美在线视频日韩欧美在线视频| 成人av毛片在线观看| 亚洲人成网站77777在线观看| 精品国产视频在线| 欧美激情黑白配| 国产精品一色哟哟哟| 视频一区二区综合| 咪咪网在线视频| 69久久夜色精品国产69蝌蚪网| 99久久国产精| 好看的日韩av电影| 国产精品一区二区三区久久久 | 99re6这里只有精品视频在线观看| 在线免费观看成人网| 欧美美女日韩| 亚洲黄色av女优在线观看| 精品人妻伦九区久久aaa片| 美日韩精品视频| 精品国产乱码久久久久久久软件| 91国内在线| 欧美猛男gaygay网站| 波多野在线播放| 国产精品毛片在线| 国产aⅴ精品一区二区三区黄| 欧美人xxx| 欧美日韩国产综合久久| 国产美女永久免费无遮挡| 一本色道久久综合亚洲精品不卡 | 国产精品久久久久久久久久久久久久| 天天干天天操av| 一区二区成人在线视频| 午夜免费一级片| 93在线视频精品免费观看| 国产成人精品视频在线观看| 免费在线国产| 色综合天天在线| 91精品人妻一区二区| 国产亚洲一级| 久久天堂国产精品| 欧美13videosex性极品| 亚洲韩国日本中文字幕| 中文字幕在线观看视频网站| 不卡视频在线看| 黄页免费在线观看视频| 欧美激情影院| 欧美一级高清免费| 国产在线一二三| 欧美午夜精品免费| 亚洲欧美卡通动漫| 国产乱妇无码大片在线观看| 成人午夜免费在线视频| 欧美1区二区| 国产成人aa精品一区在线播放| 美丽的姑娘在线观看免费动漫| 色综合久久精品| 国产视频三区四区| 精品亚洲porn| 久久www视频| 麻豆精品99| 日本高清不卡在线| 69av亚洲| 日韩亚洲欧美高清| 韩国av免费观看| 国产午夜精品一区二区三区嫩草| 91色国产在线| 亚洲综合小说| 加勒比在线一区二区三区观看| 美女高潮在线观看| 中文字幕欧美日韩va免费视频| 国产一区二区三区视频免费观看| 亚洲免费成人av| 欧美熟妇精品一区二区蜜桃视频| 香蕉久久夜色精品| 99精品视频网站| 国产厕拍一区| 国产成人精品最新| 精品国产白色丝袜高跟鞋| 精品国产伦一区二区三区观看体验 | 久久精品亚洲| 中文字幕欧美日韩一区二区三区| 日韩激情精品| 日韩美女免费视频| 日本孕妇大胆孕交无码| 亚洲色图国产精品| 亚洲春色一区二区三区| 色婷婷久久99综合精品jk白丝| 亚洲伦理一区二区三区| 91丨九色丨黑人外教| 福利片一区二区三区| 亚洲激情精品| 少妇熟女一区二区| 九九久久婷婷| av成人在线电影| 欧美日韩激情电影| 欧美激情一区二区久久久| 国产精品秘入口| 亚洲国内精品视频| 国产xxxx在线观看| 欧美亚洲国产bt| 久久精品国产亚洲av高清色欲| 国产精品乱人伦| 国产精品无码永久免费不卡| 国产一区欧美二区| 午夜激情在线观看视频| 亚洲精品婷婷| 久久久成人精品一区二区三区| 美日韩中文字幕| 粉嫩精品一区二区三区在线观看| 欧美爱爱视频| 国产精品久久久久久超碰 | 欧美性xxxx极品hd满灌| 在线免费观看亚洲视频| 国产精品理伦片| 国产吞精囗交久久久| 国产99久久久精品| 免费在线观看污网站| 肉肉av福利一精品导航| 午夜免费福利小电影| 欧美.日韩.国产.一区.二区| 五月天久久狠狠| 九色精品国产蝌蚪| 久久青青草原| 婷婷国产精品| 国产在线精品一区| 91国内精品| 99理论电影网| 久久av偷拍| 91在线免费观看网站| 日韩电影精品| 国产精品一香蕉国产线看观看| 电影一区二区三区| 欧美在线视频在线播放完整版免费观看| 日皮视频在线观看| 欧美乱妇高清无乱码| 18加网站在线| 久久国产精品久久久| 国产在线69| 欧美xxxx18性欧美| 手机av在线播放| 欧美激情在线一区| 2021天堂中文幕一二区在线观| 久久久久免费精品国产| 99thz桃花论族在线播放| 久久久综合av| 91精品产国品一二三产区| 日本三级韩国三级久久| 秋霞国产精品| 国产在线观看91精品一区| 国产一区二区三区黄网站| 91青草视频久久| ccyy激情综合| 久久精品丝袜高跟鞋| 国产a久久精品一区二区三区| 日本不卡久久| 四季av一区二区凹凸精品| 五月天男人天堂| 午夜久久一区| 国内精品视频一区二区三区| 国产精品视区| 国产真人无码作爱视频免费| 久久成人18免费观看| 日本wwww色| 91性感美女视频| 337人体粉嫩噜噜噜| 综合久久综合久久| 久久久国产精品黄毛片| 日韩欧美国产高清91| 五月激情丁香网| 日韩一区二区三区电影在线观看 | jizz国产在线| 欧美一区二区精美| 五月激情婷婷综合| 最近的2019中文字幕免费一页 | 国产精品麻豆一区二区三区| 啊v视频在线一区二区三区| 激情av在线| 国产精品久久久久久久久久ktv | 紧缚奴在线一区二区三区| 中文字幕无人区二| 国产亚洲精品超碰| 美女视频黄免费| 在线看一区二区| 亚洲黄色在线观看视频| 亚洲四色影视在线观看| 午夜小视频在线观看| 日本一欧美一欧美一亚洲视频| 91精品在线免费视频| 久久99精品国产99久久| 99国产精品免费视频观看| 精品少妇人欧美激情在线观看| 日日夜夜精品免费视频| 日本少妇xxxx软件| 欧美国产丝袜视频| 国产污视频在线观看| 欧美亚洲愉拍一区二区| 日批视频免费播放| www高清在线视频日韩欧美| jizz内谢中国亚洲jizz| 3d动漫精品啪啪一区二区三区免费 | 精品国产91九色蝌蚪| 香蕉视频在线免费看| **欧美日韩vr在线| 午夜电影一区| 亚洲欧美国产不卡| 亚洲影音一区| 性欧美18—19sex性高清| 亚洲日本乱码在线观看| 波多野结衣激情视频| 亚洲精品www久久久| 成人黄视频在线观看| 国产精品高潮呻吟久久av野狼| 国产精品中文字幕制服诱惑| 国内精品国产三级国产99| 日本欧美加勒比视频| av小说在线观看| 婷婷国产v国产偷v亚洲高清| www.色婷婷.com| 久久天天躁狠狠躁夜夜av| 日本道在线视频| 日韩电影在线一区二区三区| 五十路六十路七十路熟婆| 一区二区三区欧美亚洲| 伊人网视频在线| 中文字幕国产亚洲2019| 欧美电影免费观看| 欧美日韩大片一区二区三区| 亚洲精品影院在线观看| 久久久久亚洲AV成人网人人小说| 亚洲天堂中文字幕| 国产精品久久久午夜夜伦鲁鲁| 国产一区二区三区视频| 国产精品扒开腿做爽爽爽视频软件| 国产麻豆日韩| 亚洲黄色天堂| 成人在线电影网站| 亚洲午夜免费视频| 亚洲AV无码一区二区三区少妇| 久久视频在线直播| 24小时成人在线视频| 在线国产精品网| 精品午夜一区二区三区在线观看| 亚洲av毛片基地| 欧美日韩午夜影院| av国产在线观看| 国产欧美va欧美va香蕉在| 偷拍欧美精品| 亚欧精品在线视频| 亚洲一区二区av在线| 午夜成人免费影院| 欧美在线视频播放| 国产一区二区三区四区五区传媒| 日韩手机在线观看视频| 亚洲国产精品v| 91久久精品国产91性色69| 久久精品亚洲热| youjizz亚洲| 国产美女网站在线观看| 国产日韩v精品一区二区| 亚洲视频久久久| 欧美日韩高清区| 天堂一区二区三区四区| 亚洲欧美国产日韩综合| 一区二区成人在线| 午夜成人免费影院| 国产女精品视频网站免费| 国产精品s色| 国产又爽又黄无码无遮挡在线观看| 在线亚洲欧美专区二区| 国内精品不卡| 久久久久久欧美精品色一二三四| 视频一区视频二区中文字幕| 熟女少妇a性色生活片毛片| 精品国产伦一区二区三区观看方式 | 亚洲第一免费视频| 欧美一级黑人aaaaaaa做受| 欧美亚洲在线日韩| 年下总裁被打光屁股sp| 色婷婷综合久久久久中文一区二区| 91.xxx.高清在线| 国产美女精品在线观看| 蜜桃视频在线一区| 久久精品亚洲无码| 中文字幕精品www乱入免费视频| 久久久精品区| av免费中文字幕| 亚洲日本欧美天堂| 欧美婷婷久久五月精品三区| 91在线中文字幕| 久久国产毛片| 国产亚洲精品久久777777| 国产亚洲在线播放| 国产毛片久久久| 污污网站在线观看视频| 欧美午夜精品久久久久久浪潮 | 国产91精品在线播放| 中文在线日韩| jizz中文字幕| 亚洲精品电影网站| 大胆国模一区二区三区| 一本久道中文无码字幕av| 亚洲韩国精品一区|