1、非public方法: 只有public方法才会被Spring的事务管理器进行代理,如果一个方法不是public的,@Transactional 注解将不起作用,事务不会生效。
@Service
public class MyService {
@Transactional
private void privateMethod() {
// 该方法是private的,@Transactional注解不会生效
}
}
2、内部调用问题:
同一个Service类中methodA 方法被 @Transactional 注解修饰,但是它内部调用了 methodB 方法,而 methodB 方法没有被 @Transactional 注解修饰,此时事务有效。会共享方法A的事务。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional
public void methodA() {
// 调用methodB方法,但由于没有经过代理对象,事务不会生效
methodB();
//doSomething
}
public void methodB() {
myRepository.someDatabaseOperation();
}
}
同一个Service类中,方法B上有事务注解,方法A上没有,在A中调用B方法,事务会失效。当一个方法在同一个类中调用另一个方法时,直接调用绕过了Spring的AOP代理,导致事务管理器无法感知到对B方法的调用。因此,B方法上的@Transactional注解不会生效,事务不会被启动。(使用代理类调用B方法,则B有事务,A无事务)
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
// 方法B有事务注解
@Transactional
public void methodB() {
// 事务逻辑
myRepository.someDatabaseOperation();
}
// 方法A没有事务注解
public void methodA() {
// 方法A中调用方法B
methodB(); // 方法B的事务不会生效
}
}
3、异常处理问题:
如果在@Transactional注解修饰的方法中捕获了异常并处理,而不将异常继续向上抛出,事务可能失效。因为事务管理器无法捕获异常并进行回滚。
在Spring默认情况下,只有抛出RuntimeException
或其子类的异常才会导致事务回滚,如果抛出的异常不是RuntimeException
,则事务不会回滚。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional
public void methodA() {
try {
// 一些业务逻辑,可能会抛出异常
myRepository.someDatabaseOperation();
} catch (Exception e) {
// 捕获异常并不重新抛出
// 在此处处理异常,事务不会回滚
}
}
}
4、事务配置问题: 如果@Transactional注解未被正确配置或配置错误,也可能导致事务失效。例如,在方法A中调用了方法B,方法A的事务传播行为设置为 REQUIRES_NEW
,而方法B的事务传播行为设置为 REQUIRED
,这样可能会导致方法B开启了新的事务而不是加入方法A的事务。