点击上方蓝色“java大数据修炼之道”, 选择“设为星标”
每晚九点: 技术干货 ???? 必定奉上哈喽,各位新来的小伙伴们,大家好!由于公众号做了改版,为了保证公众号的资源能准时推送到你手里,大家记得将咱们的公众号 加星标置顶 ,在此真诚的表示感谢来源:MoDou Blog (modouxiansheng.top)

笔者文笔功力尚浅,如有不妥,请慷慨指出,必定感激不尽

学习东西要知行合一,如果只是知道理论而没实践过,那么掌握的也不会特别扎实,估计过几天就会忘记,接下来我们一起实践来学习Spring事务的传播属性。

# 传播属性

传播属性定义的是当一个事务方法碰到另一个事务方法时的处理行为,一共有七种行为,定义如下

其实只看概念的话已经很直截了当了说明了每个传播性的作用,此时我们再用具体的例子演示一下每个传播性属性下的行为。

此次演示我们使用的是H2数据库,这个数据库是作用在内存里面的,所以对于我们演示事务效果来说正好,无需我们在进行其他的配置了,我们新建一个表。将下面语句放在schema.sql文件里面即可,SpringBoot程序在启动的时候就会自动为我们在内存里面建立这样的一个表。

CREATE TABLE FOO (ID INT IDENTITY, BAR VARCHAR(64));

演示之前我们会定义两个类FooService和BarService。我们使用BarService 里面的方法进行调用FooService 中的方法。

# 环境准备

在进行事务演示之前,其实可以分为以下几种情况,根据排列组合,我们可以得出以下八种情况

  • 调用者:有无事务

  • 调用者:是否有异常

  • 被调用者:有无事务(这个是通过传播属性进行控制的)所以并不在排列组合中

  • 被调用者:是否有异常

# 异常类

其中的RollbackException是我们自己定义的一个异常类

@Service
public class BarServiceImpl implements BarService{@Autowiredprivate FooService fooService;// PROPAGATION_REQUIRED演示 无事务@Overridepublic void testRequiredNoTransactional() throws RollbackException {fooService.testRequiredTransactional();}
}

# 调用者

在BarService中定义两个方法,一个是带着事务的,一个是不带事务的

// 有事务
@Override
@Transactional(rollbackFor = Exception.class)
public void hasTransactional() throws RollbackException {}// 无事务
@Override
public void noTransactional() throws RollbackException {}

接下来我们就根据俄上面定义的八种情况进行事务传播属性的学习。

PROPAGATION_REQUIRED

在此传播属性下,被调用方是否新建事务取决去调用者是否带着事务。

想要了解这个传播属性的特性,其实我们演示上面八种情况的两个例子就够了

  • 第一种情况我们在被调用者抛出异常的情况下,如果查询不到插入的数据,那么就说明被调用者在调用者没有事务的情况下自己新建了事务。

  • 第二种情况我们在调用者抛出异常的情况下,如果查询不到插入的数据,那么就说明被调用者在调用者有事务的情况下就加入当前事务了。

我们先来看一下被调用者的类的方法例子。

@Service
public class FooServiceImpl implements FooService {@Autowiredprivate 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+")");}
}

接下来我们看一下调用者方法的例子

@Service
public class BarServiceImpl implements BarService{@Autowiredprivate FooService fooService;// 有事务@Override@Transactional(rollbackFor = Exception.class)public void hasTransactional() throws RollbackException {// 调用者有事务,抛异常  被调用者无异常fooService.testRequiredNoException();throw new RollbackException();}// 无事务@Overridepublic 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("第一种情况 {}",jdbcTemplate.queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='"+hasException+"'", Long.class));
}try {barService.hasTransactional();
}catch (Exception e){log.info("第二种情况 {}",jdbcTemplate.queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='"+noException+"'", Long.class));
}

查看打印出来的日志

2019-10-16 13:02:04.142  INFO 11869 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 13:02:04.143  INFO 11869 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

我们看到我们都没有查到相应的数据,说明数据都回滚了。此时我们应该就理解了那句话支持当前事务,如果没有就新建事务。

PROPAGATION_SUPPORTS

被调用者是否有事务,完全依赖于调用者,调用者有事务则有事务,调用者没事务则没事务。

接下来我们还是用上面的两个例子进行演示

  • 第一种情况:被调用者抛出异常的情况下,如果仍能查询到数据,说明事务没有回滚,说明被调用者没有事务

  • 第二种情况:调用者抛出异常情况下,如果查不到数据,说明两个方法在一个事务中

接下来仍然是例子演示

被调用者,只是将@Transactional 注解中的propagation 属性更换为了Propagation.SUPPORTS

// SUPPORTS传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void testSupportsHasException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_HAS_EXCEPTION+"')");throw new RollbackException();
}// SUPPORTS传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void testSupportsNoException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_NO_EXCEPTION+"')");
}

调用者和上面的例子调用一样,我们直接查看执行效果

2019-10-16 13:50:27.738  INFO 12174 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 1
2019-10-16 13:50:27.741  INFO 12174 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

我们看到了在第一种情况下查到了数据,说明在第一种情况下被调用者是没有事务的。此时我们应该就理解了这句话 支持当前事务,如果没有就不以事务的方式运行。

PROPAGATION_MANDATORY

依然是这两个例子进行演示

  • 第一种情况:因为调用者没有事务,所以此传播属性下应该是抛异常的

  • 第二种情况:被调用者的事务和调用者事务是同样的

接下来是被调用者的代码例子

// MANDATORY传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void testMandatoryHasException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_HAS_EXCEPTION+"')");throw new RollbackException();
}// MANDATORY传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void testMandatoryNoException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_NO_EXCEPTION+"')");
}

调用者和上面的例子调用一样,我们直接查看执行效果

2019-10-16 13:58:39.178 ERROR 12317 --- [           main] c.e.t.t.TransactionApplication           : org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
2019-10-16 13:58:39.276  INFO 12317 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 13:58:39.281  INFO 12317 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

我们发现和我们推测一样,说明被调用者是不会自己新建事务的,此时我们应该就理解了这句话支持当前事务,如果当前没事务就抛异常。

PROPAGATION_REQUIRES_NEW

此传播属性下,无论调用者是否有事务,被调用者都会新建一个事务

  • 第一种情况:调用者无事务,被调用者会新建事务,所以查不到数据

  • 第二种情况:调用者有事务,被调用者会新建一个事务,所以调用者抛异常影响不到被调用者,所以能查到数据

接下来我们演示代码。

被调用者

// REQUIRES_NEW传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void testRequiresNewHasException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.REQUIRES_NEW_HAS_EXCEPTION+"')");throw new RollbackException();
}// REQUIRES_NEW传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void testRequiresNewNoException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.REQUIRES_NEW_NO_EXCEPTION+"')");
}

调用者的例子和上面的相同,我们直接来看执行情况

2019-10-16 16:29:20.296  INFO 15553 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 16:29:20.298  INFO 15553 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 1

我们发现和我们的推论是一样的,说明调用者的事务和被调用者的事务完全无关。此时我们应该就理解这句话了无论当前是否有事务,都会新起一个事务。

PROPAGATION_NOT_SUPPORTED

无论调用者是否有事务,被调用者都不以事务的方法运行

同样是这两个例子

  • 第一种情况:被调用者都不会有事务,那么在抛异常之后就能查到相应的数据

  • 第二种情况:在调用者有事务的情况下,被调用者也会在无事务环境下运行,所以我们依然能查到数据

接下来验证我们的猜测

// NOT_SUPPORTED传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void testNotSupportHasException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NOT_SUPPORTS_HAS_EXCEPTION+"')");throw new RollbackException();
}// NOT_SUPPORTED传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void testNotSupportNoException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NOT_SUPPORTS_NO_EXCEPTION+"')");
}

然后查看执行结果

2019-10-16 16:38:35.065  INFO 15739 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 1
2019-10-16 16:38:35.067  INFO 15739 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 1

我们可以看到在最后两种情况都查到了数据,根据演示效果应该可以理解这句话了,不支持事务,如果当前存在事务,就将此事务挂起不以事务方式运行。

PROPAGATION_NEVER

调用者有事务,被调用者就会抛出异常

这个就不演示,相信大家看到这里应该都会明白在第一种情况下我们是能够查到数据的。在第二种情况下由于调用者带着事务,所以会抛异常。

PROPAGATION_NESTED

此传播属性下,被调用者的事务是调用者的事务的子集。

我们重点说一下NESTED的传播属性的特性

关于什么是嵌套事务的关系,我们用下面三个例子能够进行演示。

  • 第一种情况:如果查不到数据,则说明在调用者无事务情况下,被调用者会新起一个事务

  • 第二种情况:如果查不到数据,说明外层事务能够影响内层事务

  • 第三种情况:如果查到数据,说明内层事务不影响外层事务

接下来我们编写具体的代码

// NESTED传播属性-回滚事务
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testNestedHasException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_HAS_EXCEPTION+"')");// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();throw new RollbackException();
}// NESTED传播属性-不回滚事务
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testNestedNoException() throws RollbackException {jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_NO_EXCEPTION+"')");
}

然后接下来的调用者也会有点区别

@Override
@Transactional()
public void hasTransactionalNoException() throws RollbackException {// NESTED传播属性 - 调用者有事务,不抛异常  被调用者有异常jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_HAS_EXCEPTION_TWO+"')");fooService.testNestedHasException();
}

然后执行效果

2019-10-16 18:01:06.387  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 18:01:06.389  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0
2019-10-16 18:01:06.390  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第三种情况 1

可以看出来嵌套事务的本质就是外层会影响内层,内层不影响外层。而REQUIRES_NEW则是互不影响。

# 总结

到现在我们已经全部分析完了七种传播属性,从写这篇文章开始到结束其中也碰到过一些坑,有些是不自己实践一遍是根本不知道的,所以我还是建议读者看完这篇文章以后自己进行实践,演示各种情况,只有这样才能够烂熟于心。

  • 我的天! 8年开发,连登陆接口都写这么烂...

  • 颠覆认知 - MySQL数字类型如何选择?

  • 厉害了!把 HashMap 剖析的只剩渣了!

  • 阿里一面:如何保障消息100%投递成功、消息幂等性?

  • SpringBoot 中实现跨域的5种方式

  • 60个相见恨晚的神器工具!

  • 超级全面的 SpringBoot 注解介绍,每一个用途都应该清晰

看完本文有收获?请转发分享给更多人

请长按二维码,关注 Java大数据修炼之道.

推荐程序员必备公众号 

Java大数据修炼之道

公众号:

gh_9119f24d3793

推荐理由:

在这里,我们分享程序员相关技术,职场生活,行业热点资讯。不定期还会分享IT趣文和趣图。这里属于我们程序员自己的生活,工作和娱乐空间。

▼长按下方↓↓↓二维码识别关注

关注 java大数据修炼之道

每天学习java技术你想学的Java知识这里都有


京东电话面:说说你对Spring事务传播属性的理解?相关推荐

  1. Spring事务传播属性和隔离级别

    Spring事务传播属性和隔离级别 一.Spring事务传播属性(Propagation): 1) REQUIRED(默认属性) 如果存在一个事务,则支持当前事务.如果没有事务则开启一个新的事务.  ...

  2. 太难了~面试官让我结合案例讲讲自己对Spring事务传播行为的理解!

    摘要: 原创出处 sf.gg/a/1190000013341344 「handaqiang」欢迎转载,保留摘要,谢谢! 前言 基础概念 1. 什么是事务传播行为? 2. Spring 中七种事务传播行 ...

  3. Spring事务传播属性有那么难吗?看这一篇就够了

    点击上方"后端技术精选",选择"置顶公众号" 技术文章第一时间送达! 作者:不学无数的程序员 juejin.im/post/5da6eee2f265da5bb9 ...

  4. Spring 事务传播属性有那么难吗?看这一篇就够了!

    尊重原创,原文链接 学习东西要知行合一,如果只是知道理论而没实践过,那么掌握的也不会特别扎实,估计过几天就会忘记,接下来我们一起实践来学习Spring事务的传播属性. 传播属性 传播属性定义的是当一个 ...

  5. spring事务传播属性与隔离级别

    一.Propagation (事务的传播属性) Propagation : key属性确定代理应该给哪个方法增加事务行为.这样的属性最重要的部份是传播行为. 有以下选项可供使用: PROPAGATIO ...

  6. Spring事务传播属性

    1) required(默认属性) 如果存在一个事务,则支持当前事务.如果没有事务则开启一个新的事务. 被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域.如果前面的方法已经创建了事务,那么 ...

  7. Spring 事务传播行为的理解

    https://blog.csdn.net/qq_39720208/article/details/108766761

  8. mysql事务传播属性_Spring事务传播属性和隔离级别详细介绍

    1 事务的传播属性(Propagation) 1) REQUIRED ,这个是默认的属性 Support a current transaction, create a new one if none ...

  9. spring上下文是什么意思_Java程序员只会CRUD连Spring事务传播机制都不懂?

    AQS到底有什么用?难道就真的只是为了面试吗? 当然不是说AQS没用,如果你不是做基础架构或者中间件开发,你很难感受到AQS的威力.当然,学习很多时候,需要的是正向反馈,学了太多造火箭的东西,面试完就 ...

最新文章

  1. delphi 判断鼠标 左右_外设评测HyperX Pulsefire Haste游戏鼠标分享
  2. SQL操作类详细注释版
  3. 矩阵的LU分解 c++
  4. 全球及中国新能源汽车产业应用现状与运营前景规划报告2022版
  5. iOS自定义转场动画实战讲解
  6. python减法怎么表示_python运算符号之一的减法怎么用,你真的学会用python的使用方法了嘛...
  7. 回忆2020年,这一年有你们真好~
  8. 【java】getWriter() has already been called for this
  9. 计算机系和清华大学,清华大学交叉信息研究院和计算机系区别
  10. Spring核心功能--总汇
  11. 【数据分析】销售案例——杜邦分析法
  12. php网站后台不显示验证码,网站后台验证码不显示原因
  13. 身高预测c语言代码switch,C++ ,预测身高程序
  14. Rust: Descending Order
  15. 《DFS》《剪枝》Problem C. 买蛋糕
  16. 【原创】WP7向Win8移植遇到的问题及独创性解决方案
  17. Mysql 修改字段默认值问题
  18. 天桥脑科学研究院推出“对话大脑”院士论坛:国际大咖畅谈脑机接口
  19. 几款我比较满意的在线脑图工具
  20. itools安装驱动组件失败解决办法,实测有效

热门文章

  1. 我的创作纪念日--不知不觉一周年了呐
  2. 云计算python Spring cloud 微服务
  3. 【证明】相似矩阵的特征值相同
  4. H5、C3的新特性有哪些?
  5. 俄罗斯研究人员表示可访问全球所有小米宠物喂食器
  6. CMMI组织结构和岗位保证
  7. matlab 绘图(1 for 师姐王小莉)
  8. NumPy学习笔记(基础)
  9. 三立期货:掌财社怎么用筹码分布图看主力成本?
  10. 动态路由协议BGP介绍