Spring 在一个事务中开启另一个的事务

什么是事务?


什么是事务?可以参考我的这篇博客!

Spring怎么使用事务?


Spring Boot 怎么使用Spring的事务控制机制?可以参考我的这篇博客!

Spring 事务中开启新的事务的场景


通常的情况下,一般的事务直接在Service类上添加@Transactional注解,spring就会帮我们替所有方法自动生成事务。但是在某些情况下,很少出现的。我们希望在一个方法上,出现两个事务,而且2给事务之间互不影响。

如:一个用户的修改操作以及系统的删除操作

@Service
public class TestService {

    @Transactional
    public void userUpdate(){
        //用户修改操作
        systemDelete();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void systemDelete(){
        //删除系统数据操作
        throw  new RuntimeException("抛出一个删除系统数据失败的运行期异常!");
    }
}

Propagation.REQUIRES_NEW:表示如果当前存在事务,则挂起当前事务并且开启一个新事物继续执行,新事物执行完毕之后,然后在缓刑之前挂起的事务,如果当前不存在事务的话,则开启一个新事物。

上面的例子,在使用systemDelete()的时候,我显性的抛出一个运行期异常。按照最初的想法,systemDelete()会进行rollback,而用户修改操作不会。但是观察数据库会发现,这2个spring事务都进行了回滚。

那么如果我们抓住systemDelete()抛出的异常

@Service
public class TestService {

    @Transactional
    public void userUpdate(){
        //用户修改操作
        try {
            systemDelete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void systemDelete(){
        //删除系统数据操作
        throw  new RuntimeException("抛出一个删除系统数据失败的运行期异常!");
    }
}

这次会发现2个操作都成功了。说明这2个操作其实都在同一个事务之中。

怎么解决这个问题?


有2种方法可以解决这种场景

1.使用@Autowired来开启新事务

@Service
public class ServiceA {

  @Autowired
  private ServiceB serviceB;
  
  @Transactional
  public void userUpdate(){  
    //用户修改操作    
    serviceB.insert();
  }
}
@Service
public class ServiceB {

  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void systemDelete(){
    //更新系统数据操作
    throw  new RuntimeException("抛出一个更新系统失败的运行期异常");
  }
}

2.使用代理对象开启新事务

Spring 也考虑过这个问题提供了解决方案

spring配置使用


  1. spring xml配置
<aop:aspectj-autoproxy expose-proxy="true"/>

<aop:config expose-proxy="true">

<!-- spring xml配置上面2个节点的一个就可以了,效果是一样的。这个配置是让spring暴露出代理对象 -->

2.在代码的调用中要求使用代理对象去调用即可


((TestService) AopContext.currentProxy()).systemDelete();

spring boot 配置使用


当然现在主流的 spring boot 也是支持使用的 aop 代理的

1.引入spring aop依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.添加注解暴露代理对象

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class TransactionApplication {

    public static void main(String[] args) {
        SpringApplication.run(TransactionApplication.class, args);
    }

}

3.在代码的调用中要求使用代理对象去调用即可


((TestService) AopContext.currentProxy()).systemDelete();

发布了29 篇原创文章 · 获赞 0 · 访问量 378

猜你喜欢

转载自blog.csdn.net/qq_43399077/article/details/103897295