Spring @Transactional 事务回滚
来源:互联网 发布:outlook邮箱域名是什么 编辑:程序博客网 时间:2024/05/19 19:12
Spring @Transactional 事务回滚
- Spring Transactional 事务回滚
- 一问题描述
- 二JAVA异常
- 异常简介
- 异常架构
- 1Error与Exception
- 2运行时异常和非运行时异常
- 3checked异常和unchecked异常
- 三事务配置
- 1如果没有捕获异常事务会回滚
- 2如果捕获了异常事务不会回滚
- 3 throw new RuntimeException 回滚事务
- 4手动回滚既可以捕获异常事务又可以回滚
- 四声明式事务处理情况
- 五事务传播机制
- 六注意
- Spring Transactional 事务回滚
一、问题描述:
service层,一个method中包含了多条对数据库的操作。若sql1成功,sql2出错,我们希望这个method中的所有对数据的操作都会回滚,即sql1也是失败的情况。
//此方法:前边的数据库操作成功,发生数据库操作之后,后边的所有数据库操作将失败。public method(){ service.save1(User1);//操作sql1 service.save2(User2);//操作sql2 //save2执行失败,User1已经被保存到数据库中,希望被回滚 ....... service.save9(User9);//操作sql9}
二、JAVA异常:
1.异常简介
Java异常是Java提供的一种识别及响应错误的一致性机制。
Java异常机制可以使正常业务代码和异常处理代码分离,提高程序健壮性。
异常类型表示了什么错误被抛出;异常堆栈跟踪表示了代码中某个类的某一行出错;异常信息表示了错误的原因。
Java异常机制经常用到以下几个关键字:try、catch、finally、throw、throws
1)try:用于监听。try语句块内放入被监听的代码,当代码块发生异常,异常会被抛出。
public class Main { public static void main(String[] args) { try { int i = 10/0; //此处发生异常,之后的代码都不会被执行。 System.out.println("i="+i); } catch (ArithmeticException e) { System.out.println("Caught Exception"); System.out.println("e.getMessage(): " + e.getMessage()); System.out.println("e.toString(): " + e.toString()); System.out.println("e.printStackTrace():"); e.printStackTrace(); } }}
2)catch:用于捕获try语句块中发生的异常。
“int i = 10/0; ”发生异常之后,“System.out.println(“i=”+i);”并没有执行
Caught Exceptionjava.lang.ArithmeticException: / by zeroe.getMessage(): / by zero at Main.main(Main.java:5) //说明第五行出现空指针异常e.toString(): java.lang.ArithmeticException: / by zeroe.printStackTrace():
3)finally:该语句块总会被执行。
它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
public class Main { public static void main(String[] args) { try { int i = 10/0; System.out.println("i="+i); } catch (ArithmeticException e) { e.printStackTrace(); throw e; }finally { System.out.println("run finally"); } }}run finally //先执行finally块java.lang.ArithmeticException: / by zero //然后打印异常 at Main.main(Main.java:4)Exception in thread "main" java.lang.ArithmeticException: / by zero //然后执行catch,抛出异常 at Main.main(Main.java:4)
4)throw:抛出异常。
5)throws:声明抛出的异常。
2.异常架构
从上述图示可以看到,
Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。下面将详细讲述这些异常之间的区别与联系:
1)Error与Exception
Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
2)运行时异常和非运行时异常
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是unchecked异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
比如:代码校验时就可以抛出运行时异常,然后回滚事务。
if (d.getModifyReason() == "" || "".equals(d.getModifyReason()) || d.getModifyReason() == null) { message = "资质信息Tab页中的修改原因不可为空;"; throw new RuntimeException(message);}
3)checked异常和unchecked异常
checked异常:继承自java.lang.Exception(java.lang.RuntimeException除外)。
表示无效,不是程序中可以预测的。比如无效的用户输入,文件不存在,网络或者数据库链接错误。这些都是外在的原因,都不是程序内部可以控制的。
必须在代码中显式地处理。比如try-catch块处理,或者给所在的方法加上throws说明,将异常抛到调用栈的上一层。
unchecked异常:继承自java.lang.RuntimeException(而java.lang.RuntimeException继承自java.lang.Exception)。
表示错误,程序的逻辑错误。是RuntimeException的子类,比如IllegalArgumentException, NullPointerException和IllegalStateException。不需要在代码中显式地捕获unchecked异常做处理。
三、事务配置
首先配置Spring的配置文件。
在spring的配置文件中,如果数据源的defaultAutoCommit设置为True了,那么方法中如果自己捕获了异常,事务是不会回滚的,如果没有自己捕获异常则事务会回滚。
<!-- Jpa 事务配置 --><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory"/></bean><!-- 开启注解事务 --><tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="xxx" value="xxx"/> <property name="xxx" value="xxx"/> .... <property name="defaultAutoCommit" value="true" /> </bean>
1)如果没有捕获异常,事务会回滚。
若save2出错,此时save1操作会回滚。
@Transactional(rollbackOn = { Exception.class }) public void method() throws Exception { service.save1(User1); service.save2(User2);}
2)如果捕获了异常,事务不会回滚。
若save2出错,save1不会回滚。
@Transactional(rollbackOn = { Exception.class }) public void method() throws Exception { try{ service.save1(User1); service.save2(User2); }catch(Exception e){ e.printStackTrace(); } }
3) throw new RuntimeException(); 回滚事务
默认的Spring事务是:异常没有被捕获,然后回滚事务。
spring aop 异常捕获然后回滚原理:被拦截的方法需显式抛出异常,并不经过任何处理,这样aop代理才能捕获到方法的异常,并且回滚。默认情况下aop只捕获RuntimeException的异常。
@Transactional(rollbackOn = { Exception.class }) public void method() throws Exception { try{ service.save1(User1); service.save2(User2); }catch(Exception e){ throw new RuntimeException(); } }
4)手动回滚。既可以捕获异常,事务又可以回滚。
加上TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); save2方法出现异常,save1方法是会被回滚的。
@Transactional(rollbackOn = { Exception.class }) public void method() throws Exception { try{ service.save1(User1); service.save2(User2); }catch(Exception e){ e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
四、声明式事务处理情况
Spring使用声明式事务处理,默认情况下,如果被注解的数据库操作方法中发生了unchecked异常,所有的数据库操作将rollback;如果发生的异常是checked异常,默认情况下数据库操作还是会提交的。
在@Transaction注解中定义noRollbackFor和RollbackFor指定某种异常是否回滚。
@Transaction(noRollbackFor=RuntimeException.class)
@Transaction(RollbackFor=Exception.class)
这样就改变了默认的事务处理方式。
五、事务传播机制
Propagation支持7种不同的传播机制:
1)REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
2)SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
3)NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务。
4)REQUIRESNEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5)MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
6)NEVER:总是非事务地执行,如果存在一个活动事务,则抛出异常
7)NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。
六、注意
1)在需要事务管理的地方加@Transactional注解。@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。
2)@Transactional 注解只能应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
3)注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据。必须在配置文件中使用配置元素,才真正开启了事务行为。
4)通过 元素的 “proxy-target-class” 属性值来控制是基于接口的还是基于类的代理被创建。如果 “proxy-target-class” 属值被设置为 “true”,那么基于类的代理将起作用(这时需要CGLIB库cglib.jar在CLASSPATH中)。如果 “proxy-target-class” 属值被设置为 “false” 或者这个属性被省略,那么标准的JDK基于接口的代理将起作用。
5)Spring团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。
6)@Transactional 的事务开启 ,或者是基于接口的 或者是基于类的代理被创建。所以在同一个类中一个方法调用另一个方法有事务的方法,事务是不会起作用的。
- Spring @Transactional 事务回滚
- Spring中@Transactional事务回滚
- Spring中@Transactional事务回滚
- Spring中@Transactional事务回滚
- Spring中@Transactional事务回滚
- @Transactional事务回滚
- Spring中@Transactional事务回滚实例及源码
- @Transactional 事务回滚 分析
- @Transactional 事务回滚 分析
- spring@transactional事物回滚
- [spring,mysql] spring使用注解式事务声明(@Transactional)无法回滚
- Spring中Transactional不添加rollbackFor等属性时的事务回滚问题
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
- Spring中@Transactional事务回滚(含实例详细讲解,附源码)
- Dijkstra算法
- 优化Flink应用的4种方式
- Android------JNI的调用方法
- DispatcherServlet 和 ContextLoaderListener 的关系,到底用哪个?
- Android逆向_常用的定位关键代码的6种方法
- Spring @Transactional 事务回滚
- OpenCV中ROI
- 同步mysql数据到ElasticSearch的最佳实践
- Rhyme/ Hibernate5.x SessionFactory创建方式 以及org.hibernate.MappingException: Unknown entity异常
- 程序开发的基本步骤是什么?
- Esp8266上电时IO抖动解决方案
- TensorFlow and deep learning,without a PhD
- django 从入门到高手 问题集
- FL Studio常见问题之通道窗口和步进音序器的设置