当前位置:   article > 正文

【Spring】——非事务方法访问事务方法_spring非事务方法调用事务方法

spring非事务方法调用事务方法
背景简单介绍

在Spring开发中,为了使得业务的顺利开发,我们免不了需要使用事务,而在使用时,应该注意下面这一点

内容讲解

在Spring框架中,我们不能通过非事务方法去调用事务方法

代码演示
/**
 * 这个类中进行测试方法的调用
 */
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    public void testTransactionMethod() {
        try {
            transactionMethod();
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    @Override
    public void addUser() {
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = RuntimeException.class)
    public void transactionMethod() {
        try {
            userMapper.insert(new User());
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

编写一个测试类,进行我们定义方法的测试

public class UserServiceImplTest {

    @Test
    void testTransactionMethod() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.testTransactionMethod();
    }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

代码执行结果

java.lang.RuntimeException
	at com.service.impl.UserServiceImpl.testTransactionMethod(UserServiceImpl.java:20)
	at com.service.impl.UserServiceImplTest.testTransactionMethod(UserServiceImplTest.java:12)
  • 1
  • 2
  • 3

那么可以发现,我们的方法调用报错了,那么接下类我们就来分析下这到底是咋回事?

原理说明

在Spring中,我们对于事务传播的控制在TransactionDefinition这个类中

    int PROPAGATION_REQUIRED = 0; // 支持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就新建一个事务
    int PROPAGATION_SUPPORTS = 1; // 持当前事务,如果有就加入当前事务中;如果当前方法没有事务,就以非事务的方式执行;
    int PROPAGATION_MANDATORY = 2; // 支持当前事务,如果有就加入当前事务中;如果当前没有事务,就抛出异常;
    int PROPAGATION_REQUIRES_NEW = 3; // 新建事务,如果当前存在事务,就把当前事务挂起;如果当前方法没有事务,就新建事务;
    int PROPAGATION_NOT_SUPPORTED = 4; // 以非事务方式执行,如果当前方法存在事务就挂起当前事务;如果当前方法不存在事务,就以非事务方式执行;
    int PROPAGATION_NEVER = 5; // 以非事务方式执行,如果当前方法存在事务就抛出异常;如果当前方法不存在事务,就以非事务方式执行;
    int PROPAGATION_NESTED = 6; // 如果当前方法有事务,则在嵌套事务内执行;如果当前方法没有事务,则与required操作类似;
    
	// 下面是Spring事务对应的几种隔离级别,具体可以参考Mysql中的隔离级别
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;

    default int getPropagationBehavior() {
        return 0;
    }

    default int getIsolationLevel() {
        return -1;
    }

    default int getTimeout() {
        return -1;
    }

    default boolean isReadOnly() {
        return false;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 我们知道在Spring框架中,是基于xml配置文件进行各种技术的实现的,事务也不例外,在事务配置文件中,我们通过<tx:annotation-driven为开头的配置来开启事务的相关定义。而该标签在Spring中,会通过Spring中的AnnotationDrivenBeanDefinitionParser类的parse()方法进行解析,具体实现解析过程,大家可以进行源码阅读学习,这里不再说明。
  • 而对于Spring的Bean加载中,Spring会进行检测加载的该bean中方法上是否有@Transaction注解,如果有的话,Spring会给该bean创建一个子类代理类,当别处进行调用该bean下的注解方法时,Spring默认会使用该代理类进行方法调用,而在该bean中的方法进行注解方法内部调用时,就不会产生代理类,也就会出现注解失效的问题。

注解失效了,怎么办???

解决方案

一、将事务方法专门抽取出来放到一个类中进行统一管理;
二、获取本对象的代理对象,再通过该代理对象进行方法调用,使用该功能,需要在配置文件中开启一下注解<aop:aspectj-autoproxy expose-proxy="true"/>

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/224635
推荐阅读
相关标签
  

闽ICP备14008679号