手机移动端网站做多大,wordpress 公司建站,分销是什么意思,网站内部链接是怎么做的一、基本介绍 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。本篇只说明声明式注解。
1、在 spring 项目中, Transactional 注解默认会回滚运行时异常及其子类#xff0c;其它范…一、基本介绍 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。本篇只说明声明式注解。
1、在 spring 项目中, Transactional 注解默认会回滚运行时异常及其子类其它范围之外的异常 Spring 不会帮我们去回滚数据如果也想要回滚在方法或者类加上Transactional(rollbackFor Exception.class) 即可。异常继承体系如下图 Throwable 是最顶层的父类有 Error 和 Exception 两个子类。 Error表示严重的错误如OOM等Exception 可以分为运行时异常 RuntimeException 及其子类和非运行时异常 Exception 的子类中除了 RuntimeException 及其子类之外的类。 非运行时异常是检查异常 checked exceptions 一定要 try catch因为这类异常是可预料的编译阶段就检查的出来。如果不抛出异常该行代码是会报错的项目也会启动不起来。Error 和运行时异常是非检查异常 unchecked exceptions 不需要 try catch因为这类异常是不可预料的编译阶段不会检查。
2、Transactional 注解只能应用到 public 方法或者类上才有效二、简单的使用方法 只需在方法加上 Transactional 注解就可以了。
如下有一个保存数据的方法加入 transactional 注解抛出异常之后事务会自动回滚数据不会插入到数据库中。 OverrideTransactionalpublic String save(ProductModuleConfig productModuleConfig){productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException(save方法运行时异常);}return 成功;} 我们可以从控制台日志可以看出这些信息
该事务没有提交 commit因为遇到 RuntimeException 异常该事务进行了回滚数据库中也没有该条数据。
再看一个简单的使用方法 Transactional(propagation Propagation.REQUIRED, rollbackFor Exception.class)Overridepublic String save(ProductModuleConfig productModuleConfig){productModuleConfigDao.insert(productModuleConfig);try {String a null;boolean equals a.equals(2);} catch (Exception e) {e.printStackTrace();}return 成功;}
save 方法无 Transactional 注解 空指针异常没有被 try catch插入数据库操作成功空指针异常被 try catch插入数据库操作成功save 方法有 Transactional 注解 空指针异常没有被 try catch插入数据库操作失败回滚成功空指针异常被 try catch插入数据库操作成功回滚失败
三、Transactional 注解的属性介绍 事务的传播属性propagation 属性默认值为 Propagation.REQUIRED 所谓事务传播行为就是多个事务方法相互调用时事务如何在这些方法间传播。Spring 支持以下 7 种事务传播行为 名词解释
当天事务挂起需要新事物时将现有的 connection1保存起来它还有尚未提交的事务然后创建 connection2connection2 提交、回滚、关闭完毕后再把 connection1取出来完成提交、回滚、关闭等动作保存 connection1 的动作称之为事务挂起。
详解 Spring 的事务传播属性以及在写代码的过程中发生嵌套并发生事务失效的场景
再说这些之前大家先要消除一个问题 Spring 的事务是怎么实现的 Spring 本身是没有事务的只有数据库才会有事务而 Spring 的事务是借助 AOP通过动态代理的方式在我们要操作数据库的时候实际是 Spring 通过动态代理进行功能拓展在我们的代码操作数据库之前通过数据库客户端打开数据库事务如果代码执行完毕没有异常信息或者是没有 Spring 要捕获的异常信息时再通过数据库客户端提交事务如果有异常信息或者是有 Spring 要捕获的异常信息再通过数据库客户端程序回滚事务从而达到控制数据库事务的目的。 四、Transactional 注解的一些代码 demo 比如如下代码save 方法首先调用了 method1 方法然后 save 方法抛出了异常就会导致事务回滚如下两条数据都不会插入数据库。可从控制台日志信息可以看出没有提交commit事务直接回滚掉了。 OverrideTransactional(propagation Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){method1();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException(save方法运行时异常);}return 成功;}public void method1() {ProductModuleConfig productModuleConfig new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName(哈哈哈哈2);productModuleConfigDao.insert(productModuleConfig);} 现在有如下需求就算 save 方法的后面抛异常了也不能影响 method1 方法的数据插入。或许很多人的想法如下给 method1 方法加入一个新的事务这样 method1 就会在这个新的事务中执行原来的事务不会影响到新的事务。比如 method1 方法上面再加入注解 Transactional 设置 propagation 属性为 Propagation.REQUIRES_NEW代码如下 OverrideTransactional(propagation Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){method1();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException(save方法运行时异常);}return 成功;}Transactional(propagation Propagation.REQUIRES_NEW)public void method1() {ProductModuleConfig productModuleConfig new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName(哈哈哈哈2);productModuleConfigDao.insert(productModuleConfig);} 运行之后发现数据还是没有插入数据库中。怎么回事我们先看一下控制台日志打印信息。从日志内容可以看出其实两个方法都是处于同一个事务中method1 方法并没有创建一个新的事务。 大概意思在默认的代理模式下只有目标方法由外部调用才能被 Spring 的事务拦截器拦截。 在同一个类中的两个方法直接调用是不会被 Spring 的事务拦截器拦截就像上面的 save 方法直接调用了同一个类中的 method1 方法method1 方法不会被 Spring 的事务拦截器拦截也就是说 method1 方法上的注解是失效的根本没起作用。
用一个示意图加深一下印象 看上边的示意图你一定会明白了吧原因还是因为代理的时候直接把有事务的方法包在了有事务的代理方法里面了不管 method2方法是否有 Transactional 注解都会随着 method1() 的事务属性决定如果 method1() 回滚必然会导致 method2() 也会回滚。 为了解决这个问题我们可以新建一个类
Service
public class OtherServiceImpl implements OtherService {Resourceprivate ProductModuleConfigDao productModuleConfigDao;Transactional(propagation Propagation.REQUIRES_NEW)Overridepublic void method() {ProductModuleConfig productModuleConfig new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName(哈哈哈哈3);productModuleConfigDao.insert(productModuleConfig);}} 然后在 save 方法中调用 otherService.method1 方法 OverrideTransactional(propagation Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){otherService.method();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException(save方法运行时异常);}return 成功;} 这下otherService.method 方法的数据插入成功事务提交了。save 方法的数据未插入事务回滚了。继续看一下日志内容 从日志可以看出首先创建了 save 方法的事务由于 otherService.method 方法的 transactional 的 propagation 属性为 Propagation.REQUIRES_NEW新建事务如果当前存在事务就把当前事务挂起。如果当前方法没有事务就新建事务所以接着暂停了 save 方法的事务重新创建了 otherService.method 方法的事务接着 otherService.method 方法的事务提交method方法数据保存成功。接着 save 方法事务开始运行碰到错误将其插入的数据进行回滚但是method方法插入的数据不会回滚。这就印证了只有目标方法由外部调用才能被 Spring 的事务拦截器拦截。
总结
在同一个类中事务嵌套的话最终的结果应该是取决于最外层的方法事务的传播特性。如果是不同的类的事务嵌套的话外层的方法按照外层的事务传播属性执行内层的传播属性按照内层的传播属性的特点去运行。
五、Transactional 注解失效场景1、Transactional 注解应用在非 public 修饰的方法上导致注解失效 protected、private 修饰的方法上使用 Transactional 注解事务是无效
2、propagation 设置错误导致注解失败 propagation 属性设置为 PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、 PROPAGATION_NEVER 这三种类别时Transactional 注解就不会产生效果。
3、rollbackFor 设置错误Transactional 注解失败 Spring 默认回滚事务分别为抛出了未检查 unchecked 异常继承自 RuntimeException 的异常和 Error 两种情况其他异常不会回滚希望抛出其他异常 Spring 亦能回滚事务需要指定 rollbackFor 属性
4、方法之间的互相调用导致 Transactional 失效在同一个 Service 中 OverrideTransactional(propagation Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){method1();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException(save方法运行时异常);}return 成功;}Transactional(propagation Propagation.REQUIRES_NEW)public void method1() {ProductModuleConfig productModuleConfig new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName(哈哈哈哈2);productModuleConfigDao.insert(productModuleConfig);}
5、异常被 catch 捕获导致 Transactional 注解失效 Transactional(propagation Propagation.REQUIRED)Overridepublic String save(ProductModuleConfig productModuleConfig){try {productModuleConfigDao.insert(productModuleConfig);method2();} catch (Exception e) {e.printStackTrace();}return 成功;}public void method2(){String a null;boolean equals a.equals(2);} method2 方法是会报空指针异常而 save 方法对其进行了 try catch 了method2 方法的异常那 save 方法的事务就不能正常回滚数据还是会插入到数据库中的最终会报 method2 方法的空指针异常。
6、数据库引擎不支持事务 这种情况出现的概率并不高事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam那事务就从根本上失效了。