- 数据库引擎不支持事务:如果您使用的数据库引擎不支持事务,那么您将无法使用Spring事务管理。
如使用mysql且引擎是MyISAM,则事务会不起作用,原因是MyISAM不支持事务,可以改成InnoDB引擎
- spring的事务注解@Transactional只能放在public修饰的方法上才起作用,如果放在其他非public(private,protected)方法上,虽然不报错,但是事务不起作用
说白了,在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是public,则TransactionAttribute返回null,即不支持事务。
- 异常未正确处理:
这种情况下spring事务当然不会回滚,因为开发者自己捕获了异常,又没有手动抛出,换句话说就是把异常吞掉了。
如果想要spring事务能够正常回滚,必须抛出它能够处理的异常。如果没有抛异常,则spring认为程序是正常的。
@Slf4j
@Service
public class UserService {
@Transactional
public void add(UserModel userModel) {
try {
saveData(userModel);
updateData(userModel);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
- 被final修饰的方法
final修饰的方法表明方法不能被子类重写
spring事务的底层是通过aop来创建一个代理类,而代理类无法重写该方法,无法实现事务功能。
注意:如果某个方法是static的,同样无法通过动态代理,变成事务方法。
@Service
public class UserService {
@Transactional
public final void add(UserModel userModel){
saveData(userModel);
updateData(userModel);
}
}
- Spring配置错误,未被spring管理:如果您的Spring配置文件未正确配置,例如未启用事务管理器或未正确配置数据源,则可能导致事务失效。
在我们平时开发过程中,有个细节很容易被忽略。即使用spring事务的前提是:对象要被spring管理,需要创建bean实例。
通常情况下,我们通过@Controller、@Service、@Component、@Repository等注解,可以自动实现bean实例化和依赖注入的功能。
如果有一天,你匆匆忙忙的开发了一个Service类,但忘了加@Service注解,比如:
//@Service
public class UserService {
@Transactional
public void add(UserModel userModel) {
saveData(userModel);
updateData(userModel);
}
}
从上面的例子,我们可以看到UserService类没有加@Service注解,那么该类不会交给spring管理,所以它的add方法也不会生成事务。
- 方法内部调用
@Service
public class ServiceImpl implements Service {
public void test(string xxxx) {
update(xxxx);
}
@Transactional(propagation = Propagation.REQUIRED)
public void update(string xxxx) {
// update logic
}
}
因为是AOP,直接调用内部方法并非是代理类调用。处理方式详情可见:Service事务优化(方法能否被事务控制?)
可能有些人可能会有这样的疑问:这种做法会不会出现循环依赖问题?
答案:不会。其实spring Ioc内部的三级缓存保证了它,不会出现循环依赖问题。