事务的传播性

1.REQUIRED(默认模式)

方法被调用时自动开启事务,在事务范围内使用则使用同一个事务,否则开启新事务即业务方法需要在一个容器里运行,如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

@Transactional(propagation = Propagation.REQUIRED)
public void addTeacher(){
       String sql = "insert into teacher(name) values ("李亮")";
       jdbcTemplate.execute(sql);
}

经测试:无论addStudent()还是addTeacher(),如果只要有一个抛出异常,则全都回滚;不抛异常,数据正常提交

2.REQUIRES_NEW

不管是否存在事务,该方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addTeacher(){
       String sql = "insert into teacher(name) values ("李亮")";
       jdbcTemplate.execute(sql);
}

经测试:学生数据不能正确提交,教师信息被正确提交。说明这两个操作是在两个独立的事务中运行,并且只要方法被调用就开启事务。

3.Supports

自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务,即该方法在某个事务范围内被调用,则方法成为该事务的一部分,如果方法没有在事务中被调用,该方法就在没有事务的环境下执行,因为Supports默认自身不开启事务

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.SUPPORTS)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

@Transactional(propagation = Propagation.SUPPORTS)
public void addTeacher(){
       String sql = "insert into teacher(name) values ("李亮")";
       jdbcTemplate.execute(sql);
}

经测试:学生数据和教师数据都被正确提交。说明这两个操作没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功,但它们使用的却不是同一个事务,一旦出现异常将导致数据的不一致

4.NOT_SUPPORTED

声明方法不需要事务,即如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addTeacher(){
       String sql = "insert into teacher(name) values ("李亮")";
       jdbcTemplate.execute(sql);
}

经测试:学生和老师数据都正确提交。说明这两个操作没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void addTeacher(){
       String sql = "insert into teacher(name) values ("李亮")";
       jdbcTemplate.execute(sql);
}

经测试:学生数据提交失败,教师数据提交成功。说明学生操作开启了事务,老师操作没有开启事务,而是使用了本地事务

5.MANDATORY

该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.REQUIRED)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

经测试:代码报错,org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’,没有找到事务环境

6.NEVER

该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行

    @Test
    public void test{
          addStudent();
    }
    @Transactional(propagation = Propagation.REQUIRED)
    public void addStudent(){
    	  String sql = "insert into student(name) values("王华")";
          jdbcTemplate.execute(sql);
          addTeacher();
          throw new RuntimeException();   //抛异常
    }
    
    @Transactional(propagation = Propagation.NEVER)
    public void addTeacher(){
           String sql = "insert into teacher(name) values ("李亮")";
           jdbcTemplate.execute(sql);
    }

经测试:代码报错,由于学生开启了事务,当调用老师方法时由于其传播特性为never,因此报存在事务错误:org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’

7.NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点savePoint。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效(需要JDBC3.0以上支持)

嵌套事务: 内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚

@Test
public void test{
      addStudent();
}
@Transactional(propagation = Propagation.NESTED)
public void addStudent(){
	  String sql = "insert into student(name) values("王华")";
      jdbcTemplate.execute(sql);
      addTeacher();
      throw new RuntimeException();   //抛异常
}

@Transactional(propagation = Propagation.NESTED)
public void addTeacher(){
       String sql = "insert into teacher(name) values ("李亮")";
       jdbcTemplate.execute(sql);
}

经测试:代码报错,教师数据和学生数据都没有提交成功。说明其按照REQUIRED特性运行。对于嵌套事务,大家可以模拟两个数据源,一方的失败不会影响另一方

PROPAGATION_NESTED与PROPAGATION_REQUIRES_NEW 区别

它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。

  • 使用 PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务管理器的支持。
  • 使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED时,需要JDBC 3.0以上驱动及1.4以上的JDK版本支持。其它的JTA TrasactionManager实现可能有不同的支持方式。

PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。

另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交

由此可见: PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.

个人任务:如果用到事务传播性,多数是过度使用了事务,哈哈😄

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值