Spring事务失效的几种情况

Spring事务失效的几种情况

1、未被Spring管理的类中的方法

这种情况是指:没有在类上添加@Service@Repository@Component等注解将类交由Spring管理,然后该类中还有加上了@Transactional注解

例如:

@Service    //如果没有添加@Service这个注解,就是一种失效的情况
public class MyService {
    @Transactional
    public void myTransactionalMethod() {
        // 事务管理的代码
    }
}

 

2、未正确配置事务管理器

在Spring Boot中,通常会自动配置事务管理器。然而,如果你手动配置了数据源或事务管理器,并且配置不正确,事务可能会失效。确保你的DataSourcePlatformTransactionManager配置正确

这里是它的一些错误情况

  1. 数据源配置错误: 确保数据源的驱动类、连接URL、用户名和密码等配置是正确的。

  2. 事务管理器配置错误: 确保事务管理器的配置正确,并且它引用了正确的实体管理器工厂。

  3. 实体管理器工厂配置错误: 确保实体管理器工厂的配置正确,包括数据源的引用、实体类的扫描路径等。

  4. 未加入适当的数据库依赖: 确保项目的依赖中包含了正确的数据库驱动依赖。

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() {
        // 一些数据库操作
    }
}

更多了解:

百度安全验证

https://www.cnblogs.com/xiaowangbangzhu/p/17143288.html

相关推荐

  1. Spring事务失效情况

    2023-12-18 15:38:04       64 阅读
  2. Spring 事务失效情况

    2023-12-18 15:38:04       30 阅读
  3. spring 事务失效场景

    2023-12-18 15:38:04       26 阅读
  4. Spring事务失效场景

    2023-12-18 15:38:04       30 阅读
  5. Spring事务失效场景

    2023-12-18 15:38:04       36 阅读
  6. 索引失效 12 情况

    2023-12-18 15:38:04       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-18 15:38:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-18 15:38:04       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-18 15:38:04       82 阅读
  4. Python语言-面向对象

    2023-12-18 15:38:04       91 阅读

热门阅读

  1. 39.@Autowired 注解有什么作用

    2023-12-18 15:38:04       65 阅读
  2. AtomicInteger

    2023-12-18 15:38:04       62 阅读
  3. docker-镜像启动成功,外部无法访问端口及服务

    2023-12-18 15:38:04       80 阅读
  4. LeetCode解法汇总2697. 字典序最小回文串

    2023-12-18 15:38:04       82 阅读
  5. php的Url 安全的base64编码解码类

    2023-12-18 15:38:04       57 阅读
  6. 新能源行业的岗位信息

    2023-12-18 15:38:04       48 阅读
  7. postMessage解决跨域、消息传递

    2023-12-18 15:38:04       53 阅读
  8. golang os 包用法

    2023-12-18 15:38:04       65 阅读
  9. 医保dip质控系统如何实现医保控费?

    2023-12-18 15:38:04       60 阅读
  10. 医保DRG/DIP智能分析质控系统

    2023-12-18 15:38:04       55 阅读
  11. UE5Console 控制台命令

    2023-12-18 15:38:04       78 阅读
  12. UE5中C++对蓝图类的软引用方法

    2023-12-18 15:38:04       48 阅读
  13. 【uniapp小程序-分享】

    2023-12-18 15:38:04       49 阅读