关于spring事务提交的传播行为

保持事务一致性

首先我们的spring配置文件的配置如上图,除了指定方法外其他都是受事务控制,在某个aop切面配置路径下,如果方法有异常 则进行回滚,并且还是方法内涉及到增删改的回滚;

关于事务的使用:

为了保证整体方法的事务一致性,方法内如果有多处对数据进行增删改,那么最好提取成一个service进行事务控制,如果全成功,则全部提交,否则全部回滚;

以下主要是在工作中遇到的实际问题:

Service层test()方法:

while(条件){
    // 满足条件,则对数据库增删改
}

由于公司限制,不允许贴代码

这里我在Service中进行一个wile循环,如果满足条件,我就对满足条件的这一条数据进行多次增删改;

这里有个问题,不论是否出现异常,我都catch处理了,导致了事务的大量堆积,因为while循环没跑完,test()方法没执行完,事务并不会进行提交,如果while循环中的数据量过大,很有可能造成锁库锁表的可能,会造成很多问题;

实际工作中的解决方案:

方案一:向上抽取,分割成多个独立事务

我们将test()方法中的while(条件)循环向上抽取,抽取至Controller层中,然后对满足while条件的每一条数据处理时放至一个service中,这样每次循环一次时,就整体对while中的处理提交一次事务,完美解决;

方案二:事务传播,嵌套事务,创建新的事务

带有注解@Transactional(propagation=Propagation.REQUIRES_NEW)的方法走完之后,数据就会被提交入库

 while循环中如果对数据库的交互仅有一次,其他都为查询时,我建议使用这个注解,也就是说 service方法中嵌套另一个service方法,第二个service方法加上此注解,那么第二个servie方法就是新创建的事务,并进行独立提交入库;

另外需要注意方法内部调用@Transactional(propagation=Propagation.REQUIRES_NEW)注解不生效,比如A和B都在同一个方法中,A调用B,B方法是此注解,则不生效。同样,AOP拦截也拦截不到B

----REQUIRES_NEW传播说明-----------------------------------------------------------------------------------------
@Service
public class TestUserImpl implements TestUser {

    @Transactional(propagation=Propagation.REQUIRED )
    public void saveUserAll(){
        //1、保存用户--
        this.saveUser();
        //2--情况一、记录日志的方法在本service-新事务
        this.saveUserLog();
        //2--情况二、记录日志的方法在另一个LogService-新事务
        logService.saveUserLog();

         int a=1/0;//异常
    }
   
    public void saveUser() {
        User user = new User();
        userDao.save(user);

    }

    @Transactional(propagation= Propagation.REQUIRES_NEW)
    public void  saveUserLog() {
        UserLog log = new UserLog();
        UserLogDao.save(log);
    }
}
------------------------------saveUserAll在位置一,出异常,执行结果------------------------------------
       情况一、记录日志的方法在本service,saveUser回滚,saveUserLog回滚
       情况二、记录日志的方法在另一个LogService-新事务,saveUser回滚,saveUserLog不回滚
总结:要想总的方法的异常不影响 新事务方法REQUIRES_NEW的提交,新事务的方法,要写在另一个service里

以上是个人工作中的一些见解和想法,如有错误,欢迎指正。

原文地址:https://www.cnblogs.com/AlanWilliamWalker/p/11254393.html