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

聊一聊Spring事務(wù)失效的12種場(chǎng)景

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

前言

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

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

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

但如果你使用不當(dāng),它也會(huì)坑你于無形。

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

一、事務(wù)不生效

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

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

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

@Service
public class UserService {
    
    @Transactional
    private void add(UserModel userModel) {
         saveData(userModel);
         updateData(userModel);
    }
}

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

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

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // Don't allow no-public methods as required.
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
    }

    // The method may be on an interface, but we need attributes from the target class.
    // If the target class is null, the method will be unchanged.
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

    // First try is the method in the target class.
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
      return txAttr;
    }

    // Second try is the transaction attribute on the target class.
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
      return txAttr;
    }

    if (specificMethod != method) {
      // Fallback is to look at the original method.
      txAttr = findTransactionAttribute(method);
      if (txAttr != null) {
        return txAttr;
      }
      // Last fallback is the class of the original method.
      txAttr = findTransactionAttribute(method.getDeclaringClass());
      if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
      }
    }
    return null;
  }

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

2. 方法用final修飾

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

@Service
public class UserService {

    @Transactional
    public final void add(UserModel userModel){
        saveData(userModel);
        updateData(userModel);
    }
}

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

為什么?

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

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

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

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

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

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

  
    public void add(UserModel userModel) {
        userMapper.insertUser(userModel);
        updateStatus(userModel);
    }

    @Transactional
    public void updateStatus(UserModel userModel) {
        doSameThing();
    }
}

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

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

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

(1) 新加一個(gè)Service方法

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

@Servcie
public class ServiceA {
   @Autowired
   prvate ServiceB serviceB;

   public void save(User user) {
         queryData1();
         queryData2();
         serviceB.doSave(user);
   }
 }

 @Servcie
 public class ServiceB {

    @Transactional(rollbackFor=Exception.class)
    public void doSave(User user) {
       addData1();
       updateData2();
    }

 }

(2)在該Service類中注入自己

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

@Servcie
public class ServiceA {
   @Autowired
   prvate ServiceA serviceA;

   public void save(User user) {
         queryData1();
         queryData2();
         serviceA.doSave(user);
   }

   @Transactional(rollbackFor=Exception.class)
   public void doSave(User user) {
       addData1();
       updateData2();
    }
 }

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

答案:不會(huì)。

其實(shí)spring ioc內(nèi)部的三級(jí)緩存保證了它,不會(huì)出現(xiàn)循環(huán)依賴問題。

(3)通過AopContent類

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

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

@Servcie
public class ServiceA {

   public void save(User user) {
         queryData1();
         queryData2();
         ((ServiceA)AopContext.currentProxy()).doSave(user);
   }

   @Transactional(rollbackFor=Exception.class)
   public void doSave(User user) {
       addData1();
       updateData2();
    }
 }

4.未被spring管理

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

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

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

//@Service
public class UserService {

    @Transactional
    public void add(UserModel userModel) {
         saveData(userModel);
         updateData(userModel);
    }    
}

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

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

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

@Slf4j
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleService roleService;

    @Transactional
    public void add(UserModel userModel) throws Exception {
        userMapper.insertUser(userModel);
        new Thread(() -> {
            roleService.doOtherThing();
        }).start();
    }
}

@Service
public class RoleService {

    @Transactional
    public void doOtherThing() {
        System.out.println("保存role表數(shù)據(jù)");
    }
}

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

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

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

private static final ThreadLocal<Map<Object, Object>> resources =

  new NamedThreadLocal<>("Transactional resources");

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

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

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

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

有些老項(xiàng)目中,可能還在用它。

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

CREATE TABLE `category` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `one_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,
  `two_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,
  `three_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,
  `four_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

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

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

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

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

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

7.未開啟事務(wù)

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

你看到這句話可能會(huì)覺得好笑。

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

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

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

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

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

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

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

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

具體配置如下信息:

<!-- 配置事務(wù)管理器 --> 
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager"> 
    <property name="dataSource" ref="dataSource"></property> 
</bean> 
<tx:advice id="advice" transaction-manager="transactionManager"> 
    <tx:attributes> 
        <tx:method name="*" propagatinotallow="REQUIRED"/>
    </tx:attributes> 
</tx:advice> 
<!-- 用切點(diǎn)把事務(wù)切進(jìn)去 --> 
<aop:config> 
    <aop:pointcut expressinotallow="execution(* com.susan.*.*(..))" id="pointcut"/> 
    <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/> 
</aop:config>

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

二、事務(wù)不回滾

1.錯(cuò)誤的傳播特性

其實(shí),我們?cè)谑褂聾Transactional注解時(shí),是可以指定propagation參數(shù)的。

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

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

如果我們?cè)谑謩?dòng)設(shè)置propagation參數(shù)的時(shí)候,把傳播特性設(shè)置錯(cuò)了,比如:

@Service
public class UserService {

    @Transactional(propagation = Propagation.NEVER)
    public void add(UserModel userModel) {
        saveData(userModel);
        updateData(userModel);
    }
}

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

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

2.自己吞了異常

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

@Slf4j
@Service
public class UserService {
    
    @Transactional
    public void add(UserModel userModel) {
        try {
            saveData(userModel);
            updateData(userModel);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

這種情況下spring事務(wù)當(dāng)然不會(huì)回滾,因?yàn)殚_發(fā)者自己捕獲了異常,又沒有手動(dòng)拋出,換句話說就是把異常吞掉了。

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

3.手動(dòng)拋了別的異常

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

@Slf4j
@Service
public class UserService {
    
    @Transactional
    public void add(UserModel userModel) throws Exception {
        try {
             saveData(userModel);
             updateData(userModel);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new Exception(e);
        }
    }
}

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

因?yàn)閟pring事務(wù),默認(rèn)情況下只會(huì)回滾RuntimeException(運(yùn)行時(shí)異常)和Error(錯(cuò)誤),對(duì)于普通的Exception(非運(yùn)行時(shí)異常),它不會(huì)回滾。

4.自定義了回滾異常

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

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

@Slf4j
@Service
public class UserService {
    
    @Transactional(rollbackFor = BusinessException.class)
    public void add(UserModel userModel) throws Exception {
       saveData(userModel);
       updateData(userModel);
    }
}

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

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

這是為什么呢?

因?yàn)槿绻褂媚J(rèn)值,一旦程序拋出了Exception,事務(wù)不會(huì)回滾,這會(huì)出現(xiàn)很大的bug。所以,建議一般情況下,將該參數(shù)設(shè)置成:Exception或Throwable。

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

public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleService roleService;

    @Transactional
    public void add(UserModel userModel) throws Exception {
        userMapper.insertUser(userModel);
        roleService.doOtherThing();
    }
}

@Service
public class RoleService {

    @Transactional(propagation = Propagation.NESTED)
    public void doOtherThing() {
        System.out.println("保存role表數(shù)據(jù)");
    }
}

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

why?

因?yàn)閐oOtherThing方法出現(xiàn)了異常,沒有手動(dòng)捕獲,會(huì)繼續(xù)往上拋,到外層add方法的代理方法中捕獲了異常。所以,這種情況是直接回滾了整個(gè)事務(wù),不只回滾單個(gè)保存點(diǎn)。

怎么樣才能只回滾保存點(diǎn)呢?

@Slf4j
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleService roleService;

    @Transactional
    public void add(UserModel userModel) throws Exception {

        userMapper.insertUser(userModel);
        try {
            roleService.doOtherThing();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

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

三、其他

1.大事務(wù)問題

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

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

@Service
public class UserService {
    
    @Autowired 
    private RoleService roleService;
    
    @Transactional
    public void add(UserModel userModel) throws Exception {
       query1();
       query2();
       query3();
       roleService.save(userModel);
       update(userModel);
    }
}


@Service
public class RoleService {
    
    @Autowired 
    private RoleService roleService;
    
    @Transactional
    public void save(UserModel userModel) throws Exception {
       query4();
       query5();
       query6();
       saveData(userModel);
    }
}

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

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

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

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

saveData(userModel);

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

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

2.編程式事務(wù)

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

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

@Autowired
   private TransactionTemplate transactionTemplate;
   
   ...
   
   public void save(final User user) {
         queryData1();
         queryData2();
         transactionTemplate.execute((status) => {
            addData1();
            updateData2();
            return Boolean.TRUE;
         })
   }

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

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

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

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

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

2022-03-08 16:10:38

Redis事務(wù)機(jī)制

2021-09-04 07:56:44

Spring事務(wù)失效

2023-06-02 07:45:39

2023-11-04 16:28:54

2023-12-28 09:59:37

Spring容器XML

2023-02-09 10:39:15

gRPC通信模式

2022-09-26 08:03:25

VMware虛擬機(jī)

2023-07-06 13:56:14

微軟Skype

2023-03-31 09:29:18

代碼量統(tǒng)計(jì)代碼增刪

2020-09-08 06:54:29

Java Gradle語言

2021-05-12 18:02:23

方法創(chuàng)建線程

2023-07-05 08:45:18

Spring事務(wù)失效場(chǎng)景

2025-06-03 04:00:00

Spring框架配置

2021-01-28 22:31:33

分組密碼算法

2023-09-22 17:36:37

2020-05-22 08:16:07

PONGPONXG-PON

2022-02-14 16:53:57

Spring項(xiàng)目數(shù)據(jù)庫(kù)

2018-06-07 13:17:12

契約測(cè)試單元測(cè)試API測(cè)試

2023-09-27 16:39:38

2021-08-01 09:55:57

Netty時(shí)間輪中間件
點(diǎn)贊
收藏

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

亚洲永久精品唐人导航网址| av大片在线看| 一区二区国产在线观看| 精品一区二区电影| 欧美日韩大尺度| 乱人伦中文视频在线| 国产综合色产在线精品| 午夜精品www| jizzjizzjizz国产| 亚洲码欧美码一区二区三区| 婷婷综合久久一区二区三区| 日韩福利视频| 成人精品在线播放| 快she精品国产999| 欧美成人午夜视频| 91精品人妻一区二区三区| 99视频这里有精品| 欧美性猛交xxxxx水多| 欧美少妇一级片| 亚洲人视频在线观看| 黄色精品一二区| 日本人成精品视频在线| 欧美日韩免费一区二区| 国产亚洲一区二区三区不卡| 日韩色视频在线观看| 国产精品人人妻人人爽人人牛| 18加网站在线| 欧美激情自拍偷拍| 久久av免费观看| 精品国产无码一区二区| 免费成人在线观看视频| 欧美一区二三区| 国产大学生自拍| 91综合视频| 亚洲午夜未删减在线观看| 免费在线观看日韩av| 欧美视频第一| 欧美色综合久久| 久久精品免费一区二区| a'aaa级片在线观看| 亚洲色图另类专区| 水蜜桃一区二区| 免费人成黄页在线观看忧物| 不卡高清视频专区| 肥熟一91porny丨九色丨| 国产免费的av| 国产呦精品一区二区三区网站| 国产精品久久久久久久久久三级| 波多野结衣视频网站| 日韩午夜高潮| 91精品国产高清| 中文字幕一区二区三区精品| 亚洲国内欧美| 97精品视频在线| 男人的天堂一区| 极品裸体白嫩激情啪啪国产精品| 九九热最新视频//这里只有精品| 欧美日韩午夜视频| 天天综合久久| 麻豆成人在线看| 希岛爱理中文字幕| 亚洲欧美伊人| 久久久久久久久电影| 久久久全国免费视频| 欧美日韩国产探花| 欧美激情一区二区三区成人| 国产一级aa大片毛片| 国产一区观看| 91精品国产99| 久久久国产免费| 麻豆免费看一区二区三区| 国产欧亚日韩视频| 99国产精品99| 成人av一区二区三区| 看欧美日韩国产| 高清av在线| 国产精品初高中害羞小美女文| 亚洲综合欧美日韩| 影音先锋中文在线视频| 亚洲国产视频在线| 伊人成色综合网| 韩国精品主播一区二区在线观看| 欧美日韩一区小说| 中文字幕剧情在线观看| 懂色av一区二区| 亚洲欧美日韩天堂一区二区| 毛片aaaaaa| 欧美日本三区| 日韩美女免费线视频| 在线观看视频二区| 国产91高潮流白浆在线麻豆| 久久国产精品一区二区三区四区| 成年人视频在线免费观看| 成人免费在线播放视频| 久久av综合网| 99精品国自产在线| 精品国产免费一区二区三区香蕉 | 中国精品一区二区| 国产老妇另类xxxxx| 九色一区二区| 久久精品视频免费看| 五月婷婷久久综合| 污污的网站免费| 久久综合五月婷婷| 丝袜亚洲欧美日韩综合| 亚洲精品1区2区3区| 狠狠色丁香久久婷婷综合丁香| 国产精品久久九九| 婷婷视频在线| 欧美性猛交xxxx乱大交| 肉色超薄丝袜脚交| 国产麻豆精品久久| 国内偷自视频区视频综合| 在线免费观看一级片| 99免费精品在线| 黄色一级片网址| 影视一区二区三区| 亚洲国内精品在线| 亚洲国产精品免费在线观看| 日韩中文欧美在线| 国产欧美日韩在线播放| 国产视频中文字幕在线观看| 91国偷自产一区二区使用方法| 欧美激情一区二区三区p站| 波多野结衣在线观看一区二区| 午夜精品久久久久久久久久久久| 国产欧美久久久| 国产精品色哟哟| 日本一本二本在线观看| 国产一区二区三区亚洲| 欧美xxxx做受欧美| 一级黄色免费看| 国产欧美精品区一区二区三区| www.中文字幕在线| 97se亚洲| 久久久免费电影| www.国产免费| 亚洲精选一二三| 人人爽人人爽av| 国产精品99一区二区三| 国产精品美女在线观看| 色中色在线视频| 同产精品九九九| 亚洲天堂av网站| 亚洲电影成人| 精品久久sese| 理论片午夜视频在线观看| 精品日韩欧美在线| 国产亚洲精品久久777777| 国产传媒日韩欧美成人| 亚洲五码在线观看视频| 激情久久免费视频| 久久综合电影一区| 国产美女www爽爽爽视频| 亚洲欧洲韩国日本视频| av中文字幕网址| 国产精品成人av| 亚洲在线www| 免费在线中文字幕| 精品日韩一区二区三区免费视频| 精品在线免费观看视频| 不卡的av电影| 成人一级片网站| 精品国产乱码久久久久久蜜坠欲下| 国产成人精品网站| 成人动漫在线免费观看| 欧美日韩国产区一| 精品国产欧美日韩不卡在线观看| 国产老女人精品毛片久久| 日韩 欧美 视频| 精品一区免费| 国产精品永久免费视频| 成人免费视屏| 日本一区二区高清不卡| 911精品产国品一二三产区| 极品粉嫩小仙女高潮喷水久久| 精品动漫3d一区二区三区免费版| 99国产超薄丝袜足j在线观看| www.综合网.com| 日韩你懂的电影在线观看| 国产又大又黑又粗免费视频| 国产亚洲欧美一级| 日韩一区二区三区久久| 中文字幕午夜精品一区二区三区 | 88久久精品| 26uuu久久噜噜噜噜| 超碰免费在线观看| 欧美一区二区三区喷汁尤物| 亚州国产精品视频| 欧美国产在线观看| 中国男女全黄大片| 久久综合网络一区二区| 青青草原网站在线观看| 香蕉久久精品| 成人中文字幕在线观看| 91资源在线观看| 中文字幕在线亚洲| 亚洲国产999| 在线观看亚洲精品视频| 欧美黑人猛猛猛| 久久―日本道色综合久久| 手机免费av片| 亚洲欧美卡通另类91av| 在线播放 亚洲| 香蕉人人精品| 亚洲一区二区三区乱码aⅴ蜜桃女| 2020国产在线| 久久视频在线视频| 你懂的在线观看| 91精品在线观看入口| av黄色在线播放| 亚洲永久精品国产| 女人裸体性做爰全过| 99久久伊人久久99| 污免费在线观看| 青青国产91久久久久久| 免费不卡av在线| 综合久久综合| 亚洲国产精品一区二区第一页| 成人h动漫免费观看网站| 国产精品视频公开费视频| av在线网页| 欧美日韩福利视频| 午夜小视频在线| 亚洲小视频在线| 无码精品人妻一区二区| 日韩欧美区一区二| 一区二区三区精| 欧美视频中文字幕| 日日夜夜操视频| 精品日本美女福利在线观看| 精品国产精品国产精品| 国产精品无遮挡| 永久免费成人代码| 久久久噜噜噜久久中文字幕色伊伊| 图片区偷拍区小说区| 国产一区二区影院| 久久这里只精品| 男人的j进女人的j一区| 亚洲人成色77777| 国产精品美女久久久浪潮软件| 亚洲国产精品无码观看久久| 亚洲大片在线| aa在线观看视频| 亚洲一区亚洲| 日本精品一区在线观看| 99日韩精品| 国产二区视频在线播放| 一区二区黄色| 日韩精品一区二区三区久久| 99精品国产福利在线观看免费| 美女黄色免费看| 99精品国产一区二区青青牛奶| www.av中文字幕| 亚洲综合好骚| 九色porny91| 欧美aaa在线| 不卡中文字幕在线观看| 国产精品一区三区| 波多野结衣电影免费观看| 国产91在线观看| 日本一卡二卡在线| 久久亚洲影视婷婷| 美女100%露胸无遮挡| 亚洲欧洲性图库| 欧美日韩精品亚洲精品| 亚洲成av人综合在线观看| 偷偷操不一样的久久| 色婷婷久久一区二区三区麻豆| 中国a一片一级一片| 欧美美女视频在线观看| www.久久色| 精品香蕉一区二区三区| 二人午夜免费观看在线视频| 久久精品小视频| www欧美xxxx| 国产成人精品一区二区三区| 国产精品亲子伦av一区二区三区| 91热精品视频| 奇米影视777在线欧美电影观看| 日本不卡一二三区| 欧美高清不卡| 欧美极品欧美精品欧美图片| 乱一区二区av| 国产精品熟妇一区二区三区四区| 99精品国产99久久久久久白柏 | 丰满少妇被猛烈进入| 亚洲精品视频免费| 快射av在线播放一区| 午夜精品一区二区三区av| 三上悠亚国产精品一区二区三区| 国产综合香蕉五月婷在线| 国产精品极品在线观看| 日韩久久不卡| 精品动漫3d一区二区三区免费版| 九色porny91| 成人精品视频一区二区三区| 手机看片福利视频| 一区二区三区久久| 日韩精品一区二区亚洲av观看| 日韩一级片网址| 九色视频在线播放| 九九九久久国产免费| 欧美一区久久久| 国产91免费视频| 日韩精品1区| 男人插女人视频在线观看| 久久精品久久综合| 欧洲女同同性吃奶| 一区二区三区成人| 亚洲在线精品视频| 日韩精品中文字幕久久臀| av网站免费在线观看| 国产91露脸中文字幕在线| 视频精品一区| 伊人久久大香线蕉午夜av| 99在线精品免费视频九九视 | 成人在线国产视频| 久久国产综合精品| 成人午夜福利一区二区| 亚洲国产精品久久人人爱蜜臀| 91久久国语露脸精品国产高跟| 亚洲欧美一区二区三区四区| 福利网站在线观看| 91日韩在线播放| 日韩中文在线电影| 激情五月亚洲色图| 26uuu亚洲| 日本天堂网在线观看| 日韩欧美国产三级| 日本中文字幕在线视频| 国产成人拍精品视频午夜网站| 里番精品3d一二三区| 福利视频免费在线观看| 国产盗摄一区二区三区| 午夜写真片福利电影网| 欧美精选在线播放| 第九色区av在线| 国产精品久久久久福利| 亚洲性视频大全| 不卡影院一区二区| 国产亚洲欧美在线| 蜜臀尤物一区二区三区直播| 亚洲色图15p| 网友自拍亚洲| 日本不卡免费新一二三区| 免费欧美日韩| 成人性生交大免费看| 色综合久久综合网97色综合 | 国产精品对白| 欧美三级午夜理伦三级老人| 精品一区二区三区免费视频| 在线观看日本黄色| 欧美高清视频一二三区 | 国产日韩精品在线播放| 色天天久久综合婷婷女18| 色播五月激情五月| 亚洲人成在线观看一区二区| 国产毛片毛片毛片毛片| 欧美老肥婆性猛交视频| 豆花视频一区二区| 欧美 国产 综合| 久久久国产午夜精品 | 美腿丝袜亚洲综合| fc2ppv在线播放| 欧美一二三四区在线| 欧美精品videosex| 精品久久久久久一区| 久久综合九色| 一级性生活免费视频| 日韩精品一区二| 亚洲美女炮图| 亚洲成人18| 国产毛片精品视频| 日韩免费观看一区二区| 一区二区国产精品视频| 欧美亚洲人成在线| 996这里只有精品| 成人黄色大片在线观看 | 日本不卡视频一二三区| 日本黄色片免费观看| 亚洲国产小视频| 亚洲成人av观看| wwwjizzjizzcom| 久久网这里都是精品| 91极品身材尤物theporn| 欧美华人在线视频| 精品国产精品国产偷麻豆| 九九久久久久久| 精品久久久视频| 麻豆影院在线观看| 精品久久久久久中文字幕动漫| 捆绑调教一区二区三区| 久久不卡免费视频| 少妇精69xxtheporn| 久久中文资源| 亚洲午夜激情影院| 欧美日韩国产在线看| 国产在线激情| 日本高清一区|