其他分享
首页 > 其他分享> > [Spring] Spring 探秘 之 事务配置(二)

[Spring] Spring 探秘 之 事务配置(二)

作者:互联网

[Spring] Spring 探秘 之 事务配置(二)

目录

手机用户请横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以加入『知识星球』获取长期知识分享服务。

前文

>>> [Spring] Spring 探秘 之 事务配置(一)

Spring 事务传播规则

当我们调用一个基于Spring的Service接口方法(如UserService#addUser())时,它将运行于Spring管理的事务环境中,Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作,因此就会产生服务接口方法嵌套调用的情况, Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:

在这里插入图片描述

事务传播行为类型 说明
PROPAGATION_REQUIRED 指定当前方法必需在事务环境中运行,如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 指定当前方法加入当前事务环境,支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 指定当前方法必须加入当前事务环境,使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 指定当前方法总是会为自己发起一个新的事务,如果发现当前方法已运行在一个事务中,则原有事务被挂起,我自己创建一个属于自己的事务,直我自己这个方法commit结束,原先的事务才会恢复执行。
PROPAGATION_NOT_SUPPORTED 指定当前方法以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,等我以非事务的状态运行完,再继续原来的事务。
PROPAGATION_NEVER 指定当前方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常,只有没关联到事务,才正常执行。(以非事务方式执行,如果当前存在事务,则抛出异常)
PROPAGATION_NESTED 指定当前方法执行时,如果已经有一个事务存在,则运行在这个嵌套的事务中.如果当前环境没有运行的事务,就新建一个事务,并与父事务相互独立,这个事务拥有多个可以回滚的保证点。就是指我自己内部事务回滚不会对外部事务造成影响,只对DataSourceTransactionManager事务管理器起效。

说明:

当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制.

事务隔离的必要性

而隔离级别就是解决以上问题的。

隔离级别 说明
ISOLATION_DEFAULT Spring默认选项,使用数据库的默认隔离级别(不同的数据库会有所区别)
ISOLATION_READ_UNCOMMITTED 读未提交:允许读取还未提交的改变了的数据,可能导致脏读、幻读、不可重复读
ISOLATION_READ_COMMITTED 读已提交:允许在并发事务已经提交后读取,可防止脏读(幻读和不可重复读可能会发生)
ISOLATION_REPEATABLE_READ 可重复读:对相同字段的读取是一致的(除了数据库事务改变),防止脏读、不可重复读。
ISOLATION_SERIALIZABLE 可序列化:串行化,完全遵从ACID的隔离级别,效率也是最低的。

Pg、Oracle默认的隔离级别为读已提交。

事务嵌套

REQUIRED(REQUIRES_NEW) 内层会新建一个事务,代码执行完成后,直接提交事务

/*UserInfoServiceImpl.propagationRequired*/

@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
    log.debug("---------------propagationRequired");
    transationSevice.propagationRequiresNew();
    log.debug("---------------propagationRequired");
}

/*TransationSeviceImpl.propagationRequiresNew*/
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNew() {
    log.debug("---------------propagationRequiresNew");
}

日志

在这里插入图片描述

在这里插入图片描述

REQUIRED(REQUIRES_NEW[Exception]) 内层事务异常不会影响外层事务


/*UserInfoServiceImpl.propagationRequiredRollback*/

@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequiredRollback() {
    try {
         log.debug("---------------propagationRequiredRollback");
         transationSevice.propagationRequiresNewRollBack();
         log.debug("---------------propagationRequiredRollback");
     } catch (Exception e) {
         log.error("---------------excaption");
     }
 }

/*TransationSeviceImpl.propagationRequiresNewRollBack*/
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNewRollBack() {
    log.debug("-------------------propagationRequiresNewRollBack");
    throw new RuntimeException();
}

在这里插入图片描述

REQUIRED(REQUIRES_NEW)[Exception] 外层事务异常不会影响内层事务

/*UserInfoServiceImpl.propagationRequiredCurrentRollback*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequiredCurrentRollback() {
    log.debug("---------------propagationRequiredCurrentRollback");
    transationSevice.propagationRequiresNew();
    log.debug("---------------propagationRequiredCurrentRollback");
    throw new RuntimeException();
}

/*TransationSeviceImpl.propagationRequiresNew*/
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNew() {
    log.debug("---------------propagationRequiresNew");
}

在这里插入图片描述

REQUIRED(NESTED)内部嵌套事务结束后和外部事务一起提交


/*UserInfoServiceImpl.propagationRequiredAndNested*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequiredAndNested() {
   log.debug("---------------propagationRequiredAndNested");
   UserInfo userInfo = new UserInfo("xx1",1,"xx1","xx","xx",1,new Date());
   insertSelective(userInfo);
   transationSevice.propagationNested();
   log.debug("---------------propagationRequiredAndNested");
   userInfo = new UserInfo("xx2",1,"xx2","xx","xx",1,new Date());
   insertSelective(userInfo);
}

/*TransationSeviceImpl.propagationNested*/
@Override
@Transactional(propagation = Propagation.NESTED)
public void propagationNested() {
   log.debug("-------------------propagationNested");
   UserInfo userInfo = new UserInfo("xx3",1,"xx1","xx","xx",1,new Date());
   userInfoService.insertSelective(userInfo);
}

在这里插入图片描述

在这里插入图片描述

REQUIRED(NESTED[Exception]) 虽然内部事务嵌套在外部事务中,但内部回滚时只回滚内部的操作不影响外部

/*UserInfoServiceImpl.propagationRequiredAndNested*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequiredAndNested() {
    try {
        log.debug("---------------propagationRequiredAndNested");
        UserInfo userInfo = new UserInfo("xx1", 1, "xx1", "xx", "xx", 1, new Date());
        insertSelective(userInfo);
        transationSevice.propagationNested();
        log.debug("---------------propagationRequiredAndNested");
        userInfo = new UserInfo("xx2", 1, "xx2", "xx", "xx", 1, new Date());
        insertSelective(userInfo);
    } catch (Exception e) {
        log.error("---------------excaption");
    }
}

/*TransationSeviceImpl.propagationNested*/
@Override
@Transactional(propagation = Propagation.NESTED)
public void propagationNested() {
   log.debug("-------------------propagationNested");
   UserInfo userInfo = new UserInfo("xx3",1,"xx1","xx","xx",1,new Date());
   userInfoService.insertSelective(userInfo);
   throw new RuntimeException();
}

在这里插入图片描述

在这里插入图片描述

REQUIRED(NESTED)[Exception] 外部事务回滚导致内部也不会提交

/*UserInfoServiceImpl.propagationRequiredAndNested*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequiredAndNested() {
      log.debug("---------------propagationRequiredAndNested");
      UserInfo userInfo = new UserInfo("xx1", 1, "xx1", "xx", "xx", 1, new Date());
      insertSelective(userInfo);
      transationSevice.propagationNested();
      log.debug("---------------propagationRequiredAndNested");
      userInfo = new UserInfo("xx2", 1, "xx2", "xx", "xx", 1, new Date());
      insertSelective(userInfo);
      throw new RuntimeException();
}

/*TransationSeviceImpl.propagationNested*/
@Override
@Transactional(propagation = Propagation.NESTED)
public void propagationNested() {
   log.debug("-------------------propagationNested");
   UserInfo userInfo = new UserInfo("xx3",1,"xx1","xx","xx",1,new Date());
   userInfoService.insertSelective(userInfo);
}

REQUIRED(NESTED)[Exception]事务日志

REQUIRED(NESTED)[Exception]数据表

REQUIRED(REQUIRED[Exception]) 内部回滚,外部进行异常捕获,试图使当前事务不回滚的情况下报错

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

错误信息提示为已将当前事务标记为回滚状态

/*UserInfoServiceImpl.propagationRequired*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
   try {
       log.debug("---------------propagationRequired");      
       transationSevice.propagationRequired();
       log.debug("---------------propagationRequired");
   } catch (Exception e) {
       log.error("---------------excaption");
   }
}

/*TransationSeviceImpl.propagationRequired*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
   log.debug("----------------propagationRequired");
   throw new RuntimeException();
}

REQUIRED(REQUIRED[Exception])事务日志

REQUIRED(REQUIRED[Exception])数据表为空

尝试在外层进行事务提交

@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
    UserInfo userInfo = new UserInfo("xx1", 1, "xx1", "xx", "xx", 1, new Date());
    insertSelective(userInfo);
    transationSevice.propagationNested();
    try {
        log.debug("---------------propagationRequired");
        transationSevice.propagationRequired();
        log.debug("---------------propagationRequired");
    } catch (Exception e) {
        log.error("---------------excaption");
    }
    UserInfo userInfo2 = new UserInfo("xx2", 1, "xx1", "xx", "xx", 1, new Date());
    insertSelective(userInfo2);
    transationSevice.propagationNested();
}

REQUIRED(REQUIRED[Exception])事务日志

REQUIRED(REQUIRED[Exception])数据表为空

相同传播规则的事务,内部异常会导致整体事务无法提交,直接回滚。

事务注解 和 AOP切面的环绕通知

/*TransationSeviceImpl.propagationRequired*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
      log.debug("---------------propagationRequired");
      propagationRequiresNew();//或this.propagationRequiresNew();
      log.debug("---------------propagationRequired");
}

/*TransationSeviceImpl.propagationRequiresNew*/
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNew() {
    log.debug("---------------propagationRequiresNew");
}

内部调用无法触发事务

/*TransationSeviceImpl.propagationRequired*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
      log.debug("---------------propagationRequired");
      propagationRequiresNew();
      log.debug("---------------propagationRequired");
}

/*TransationSeviceImpl.propagationRequiresNew2*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNew2() {
    log.debug("---------------propagationRequiresNew2");
}

非接口定义的内部方法无法触发事务


@Resource
private UserInfoService userInfoService;

/*TransationSeviceImpl.propagationRequired*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void propagationRequired() {
      log.debug("---------------propagationRequired");
      userInfoService.propagationRequiresNew();
      log.debug("---------------propagationRequired");
}

/*TransationSeviceImpl.propagationRequiresNew2*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void propagationRequiresNew2() {
    log.debug("---------------propagationRequiresNew2");
}

接口实例注入后触发AOP环绕通知

备注

Spring Boot 只开启事务日志

logging:
  level:
    root: WARN
    com:
      example: DEBUG
    org:
      springframework:
        jdbc: DEBUG

REFRENCES


更多

扫码关注架构探险之道,回复『源码』,获取本文相关源码

.

扫码加入知识星球,获取珍贵笔记、视频、电子书的等资源。

.

标签:事务,log,Spring,---------------,debug,new,探秘,propagationRequired
来源: https://blog.51cto.com/u_15263565/2884857