作者:不学无数的程序员来源:https://juejin.im/post/5da6eee2f265da5bb977d65c
学习东西要知行合一,如果只是知道理论而没实践过,那么掌握的也不会特别扎实,估计过几天就会忘记,接下来我们一起实践来学习Spring事务的传播属性。
传播属性
传播属性定义的是当一个事务方法碰到另一个事务方法时的处理行为,一共有七种行为,定义如下
![5a1a862086df2e407206bfea806bc537.png](https://i-blog.csdnimg.cn/blog_migrate/f9eb967af3a5a11179921a8e2104051f.jpeg)
其实只看概念的话已经很直截了当了说明了每个传播性的作用,此时我们再用具体的例子演示一下每个传播性属性下的行为。
此次演示我们使用的是H2数据库,这个数据库是作用在内存里面的,所以对于我们演示事务效果来说正好,无需我们在进行其他的配置了,我们新建一个表。将下面语句放在schema.sql文件里面即可,SpringBoot程序在启动的时候就会自动为我们在内存里面建立这样的一个表。
CREATE TABLE FOO (ID INT IDENTITY, BAR VARCHAR(64));
演示之前我们会定义两个类FooService和BarService。我们使用BarService里面的方法进行调用FooService中的方法。
环境准备
在进行事务演示之前,其实可以分为以下几种情况,根据排列组合,我们可以得出以下八种情况
- 调用者:有无事务
- 调用者:是否有异常
- 被调用者:有无事务(这个是通过传播属性进行控制的)所以并不在排列组合中
- 被调用者:是否有异常
![9c7d943a1ae0ff5d1a579b6c9a677b61.png](https://i-blog.csdnimg.cn/blog_migrate/c5ac32bff77941d59753fedcda834134.jpeg)
异常类
![abd8d85f33df4d7ce18aaabe9d94a047.png](https://i-blog.csdnimg.cn/blog_migrate/3b805ad6611255ef28082c49ae7bee91.jpeg)
接下来我们就根据俄上面定义的八种情况进行事务传播属性的学习。
PROPAGATION_REQUIRED
在此传播属性下,被调用方是否新建事务取决去调用者是否带着事务。
想要了解这个传播属性的特性,其实我们演示上面八种情况的两个例子就够了
![581ab474ab549ead3f3410e5c48743fb.png](https://i-blog.csdnimg.cn/blog_migrate/89a62d6975750078413bb47aba4b1235.jpeg)
- 第一种情况我们在被调用者抛出异常的情况下,如果查询不到插入的数据,那么就说明被调用者在调用者没有事务的情况下自己新建了事务。
- 第二种情况我们在调用者抛出异常的情况下,如果查询不到插入的数据,那么就说明被调用者在调用者有事务的情况下就加入当前事务了。
我们先来看一下被调用者的类的方法例子。
@Servicepublic class FooServiceImpl implements FooService { @Autowired private JdbcTemplate jdbcTemplate; // REQUIRED传播属性-被调用者有异常抛出 @Override @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED) public void testRequiredHasException() throws RollbackException { jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ("+Global.REQUIRED_HAS_EXCEPTION+")"); throw new RollbackException(); } // REQUIRED传播属性-被调用者无异常抛出 @Override @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED) public void testRequiredNoException() throws RollbackException { jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ("+Global.REQUIRED_NO_EXCEPTION+")"); }}
接下来我们看一下调用者方法的例子
@Servicepublic class BarServiceImpl implements BarService{ @Autowired private FooService fooService; // 有事务 @Override @Transactional(rollbackFor = Exception.class) public void hasTransactional() throws RollbackException { // 调用者有事务,抛异常 被调用者无异常 fooService.testRequiredNoException(); throw new RollbackException(); } // 无事务 @Override public void noTransactional() throws RollbackException { // 调用者无事务,不抛异常 被调用者有异常 fooService.testRequiredHasException(); }}
此时我们在程序调用时进行查询
String noException = Global.REQUIRED_NO_EXCEPTION;String hasException = Global.REQUIRED_HAS_EXCEPTION;try { barService.noTransactional();}catch (Exception e){ log.info("第一种情况 {}