Spring事务失效的几种情况
Spring事务失效的几种情况
1、未被Spring管理的类中的方法
这种情况是指:没有在类上添加
@Service
、@Repository
、@Component
等注解将类交由Spring管理,然后该类中还有加上了@Transactional注解
例如:
@Service //如果没有添加@Service这个注解,就是一种失效的情况
public class MyService {
@Transactional
public void myTransactionalMethod() {
// 事务管理的代码
}
}
?
2、未正确配置事务管理器
在Spring Boot中,通常会自动配置事务管理器。然而,如果你手动配置了数据源或事务管理器,并且配置不正确,事务可能会失效。确保你的DataSource
和PlatformTransactionManager
配置正确
这里是它的一些错误情况
数据源配置错误: 确保数据源的驱动类、连接URL、用户名和密码等配置是正确的。
事务管理器配置错误: 确保事务管理器的配置正确,并且它引用了正确的实体管理器工厂。
实体管理器工厂配置错误: 确保实体管理器工厂的配置正确,包括数据源的引用、实体类的扫描路径等。
未加入适当的数据库依赖: 确保项目的依赖中包含了正确的数据库驱动依赖。
3、异常被捕获而不重新抛出
Spring事务默认只对未捕获的运行时异常进行回滚。如果在事务内捕获了异常并没有重新抛出,事务可能不会回滚。?
看如下的代码,这个哪里有问题呢?我们该如何来修改它
@Transactional
public void myTransactionalMethod() {
try {
// 可能会抛出异常的代码
// ...
} catch (Exception e) {
// 异常被捕获,但没有重新抛出
// 可能导致事务不回滚
log.error("An error occurred: {}", e.getMessage());
}
}
在上述代码中,如果在
try
块中的代码抛出了异常,但在catch
块中没有重新抛出该异常,那么事务可能不会回滚。因为Spring默认只回滚未捕获的运行时异常。为了确保事务能够正常回滚,应该在catch
块中将异常重新抛出或采取其他适当的措施。下面是它修改之后的代码:
@Transactional
public void myTransactionalMethod() {
try {
// 可能会抛出异常的代码
// ...
} catch (Exception e) {
// 将异常重新抛出
throw e;
}
}
4、自调用问题
这个就是一般最容易出现的问题了(个人感觉)
就是在同一个类中,直接调用了另一个加上了@Transactional注解的方法,使Spring可能无法截获这个调用(因为调用并没有经过代理对象),所以事务失效了。
就是下面例子这种情况:
@Service
public class MyService {
@Transactional
public void methodA() {
// 一些数据库操作
}
public void methodB() {
// 一些逻辑操作
methodA(); // 在同一个类中直接调用methodA
}
}
在这个例子中,
methodB
在同一个类中直接调用了methodA
。Spring的AOP代理没有介入,即没有生成代理对象,所以methodA
可能就受不到@Transactional
注解的影响。?
那如何来解决这种情况呢?
解决方法:
1、使用代理对象调用方法A(通过GPT了解的)
2、使用
AopContext.currentProxy()
获取当前代理对象(黑马视频中学的)
方法一:?使用代理对象调用方法A
@Service
public class MyService {
@Autowired
private MyService self; // 自动注入当前类的实例
@Transactional
public void methodB() {
// 通过代理对象调用methodA
self.methodA();
}
public void methodA() {
// 一些数据库操作
}
}
?方法二:使用AopContext.currentProxy()
获取当前代理对象
//使用前提:需要在SpringBoot启动类上加上@EnableAspectJAutoProxy(exposeProxy = true)
//该注解目的是:暴露代理对象,如果没有暴露,我们是拿不到代理对象的
@Service
public class MyService {
@Transactional
public void methodB() {
// 获取当前代理对象
MyService proxy = (MyService) AopContext.currentProxy();
// 通过代理对象调用methodA
proxy.methodA();
}
public void methodA() {
// 一些数据库操作
}
}
更多了解:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!