疑惑
- @Transactional注解只能应用于 public 方法,如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。大神说是由于Spring AOP 的本质决定的,暂时还不明白为什么。
验证
pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
User.java
package me.zhao.entity;
public class User {
private Integer id;
private String name;
private Integer age;
// getter setter
}
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请求,同样返回了除零异常,但是数据库没有插入,即事务回滚;
总结
- @Transactional 注解只能应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会有事务行为。
AbstractFallbackTransactionAttributeSource中getTransactionAttribute方法调用了其本身的computeTransactionAttribute方法,如下图,其中allowPublicMethodsOnly方法由子类AnnotationTransactionAttributeSource实现,该子类方法中默认是true,所以当你加了事务注解的方法不是public时,该方法直接返回null
接下来是AopUtils.canApply方法
由于canApply方法返回false所以没有添加对应的事务Advisor