一般我们使用@Transactional注解设置事务
- @Transactional修饰在方法上事务生效
@Transactional
public void saveUser(User user) {
userRespository.save(user);
}
- 方法一有事务,调用自己类或其他类的无事务方法,事务生效
@Transactional
public void saveUser(User user) {
test(user);
}
private User test(User user) {
User user1 = userRespository.save(user);
int i = 1/0;
return user1;
}
- 方法一无事务,调用自己类有事务方法,事务失效
public void saveUser(User user) {
test(user);
}
@Transactional
public User test(User user) {
User user1 = userRespository.save(user);
int i = 1/0;
return user1;
}
为什么会失效呢?:其实原因很简单,Spring在扫描Bean的时候会自动为标注了@Transactional注解的类生成一个代理类(proxy),当有注解的方法被调用的时候,实际上是代理类调用的,代理类在调用之前会开启事务,执行事务的操作,但是同类中的方法互相调用,相当于this.B(),此时的B方法并非是代理类调用,而是直接通过原有的Bean直接调用,所以注解会失效。
解决方案参考:同类方法调用事务失效问题解决
4.内部使用了try catch,吃掉异常,导致事务不生效。 这是时候推荐使用手动回滚事务
public User test(User user) {
try {
//开启事务
// DefaultTransactionDefinition df = new DefaultTransactionDefinition();
// df.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// TransactionStatus transactionStatus = mysqlTransactionManager.getTransaction(df);
User user1 = userRespository.save(user);
int i = 1/0;
//提交事务
// mysqlTransactionManager.commit(transactionStatus);
}catch (Exception e) {
//回滚事务
//mysqlTransactionManager.rollback(transactionStatus);
}
}
- 在事务的方法内部,另起子线程执行 db 操作,test方法导致事务失效
@Transactional
public void saveUser(User user) {
new Thread(() -> {
test(user);
}).start();
}
数据库引擎采用的是MyISAM,MyISAM不支持事务,InnoDB支持事务
- Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类)进行回滚,业务自定义的异常不支持回滚
解决办法就是:@Transactional(rollbackFor = Exception.class),且在方法中throws Exception
-
@Transactional修饰的方法必须是public权限的,否则也会事务失效。
-
方法一有事务,调用方法二也有事务。事务生效
@Transactional
public void saveUser(User user) {
test(user);
}
@Transactional
public User test(User user) {
User user1 = userRespository.save(user);
int i = 1/0;
return user1;
}
@Transactional注解的默认传播行为为Propagation.REQUIRED
二、事务传播行为
事务传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
PROPAGATION_SUPPORTS、PROPAGATION_NEVER 事务都会引起事务失效。 比如方法A没有事务,调用方法B有事务,但是PROPAGATION_SUPPORTS类型的,就会导致事务失效。