Spring注解事务不支持 protected private 方法的原因

疑惑

  1. @Transactional注解只能应用于 public 方法,如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。大神说是由于Spring AOP 的本质决定的,暂时还不明白为什么。

验证

pom依赖

 
  1. <dependencies>

  2. <dependency>

  3. <groupId>org.springframework.boot</groupId>

  4. <artifactId>spring-boot-starter-web</artifactId>

  5. </dependency>

  6.  
  7. <dependency>

  8. <groupId>org.springframework.boot</groupId>

  9. <artifactId>spring-boot-starter-jdbc</artifactId>

  10. </dependency>

  11.  
  12. <dependency>

  13. <groupId>mysql</groupId>

  14. <artifactId>mysql-connector-java</artifactId>

  15. <version>5.1.30</version>

  16. <scope>runtime</scope>

  17. </dependency>

  18. <dependency>

  19. <groupId>org.springframework.boot</groupId>

  20. <artifactId>spring-boot-starter-test</artifactId>

  21. <scope>test</scope>

  22. </dependency>

  23. </dependencies>

application.properties

 
  1. spring.datasource.url=jdbc:mysql://localhost:3306/test

  2. spring.datasource.username=root

  3. spring.datasource.password=root

  4. spring.datasource.driver-class-name=com.mysql.jdbc.Driver

User.java

 
  1. package me.zhao.entity;

  2.  
  3. public class User {

  4.  
  5. private Integer id;

  6.  
  7. private String name;

  8.  
  9. private Integer age;

  10.  
  11. // getter setter

  12. }

TestController.java

package me.zhao.controller;


import me.zhao.entity.User;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.transaction.annotation.Transactional;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RestController;


@RestController

public class TestController {


private final JdbcTemplate jdbcTemplate;


@Autowired

public TestController(JdbcTemplate jdbcTemplate) {

this.jdbcTemplate = jdbcTemplate;

}


/**

* 方法为 protected 发生异常时spring 事务不回回滚

* @param user 用户

* @return

*/

@PostMapping("/insert1")

@Transactional(rollbackFor = Exception.class)

protected int insert1(User user) {

String sql = "INSERT user(name, age) VALUES(? ,?)";

int num = jdbcTemplate.update(sql, user.getName(), user.getAge());

int a = 1 / 0;

return num;

}


/**

* 方法为 public 发生异常时spring 事务进行回滚

* @param user

* @return

*/

@PostMapping("/insert2")

@Transactional(rollbackFor = Exception.class)

public int insert2(User user) {

String sql = "INSERT user(name, age) VALUES(? ,?)";

int num = jdbcTemplate.update(sql, user.getName(), user.getAge());

int a = 1 / 0;

return num;

}

}

验证

方法为 protect,insert2方法为public。

左侧的两张图为 insert1请求,可以看出即使返回了 除零异常,数据库依然插入成功了,即没有回滚;

右侧的两张图为 insert2请求,同样返回了除零异常,但是数据库没有插入,即事务回滚;

insert1请求      insert2请求

                          

总结

  1. @Transactional 注解只能应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会有事务行为。

 

在这里插入图片描述

AbstractFallbackTransactionAttributeSource中getTransactionAttribute方法调用了其本身的computeTransactionAttribute方法,如下图
在这里插入图片描述,其中allowPublicMethodsOnly方法由子类AnnotationTransactionAttributeSource实现,该子类方法中默认是true,所以当你加了事务注解的方法不是public时,该方法直接返回null
在这里插入图片描述
接下来是AopUtils.canApply方法
在这里插入图片描述
由于canApply方法返回false所以没有添加对应的事务Advisor