通过这篇文章,你将学习到Spring框架中中事务的传递
1. 简介
在处理Spring管理的事务时,开发人员可以以传播的方式定义事务的行为。换句话说,开发人员能够决定业务方法如何被封装在逻辑和物理事务中。来自不同Spring bean的不同方法可以在相同的事务范围或分割为多个嵌套的事务中执行。这可能导致像内部事务产生的结果如何影响外部事务的细节。我们将在下一节中看到Spring中不同的传播机制的不同行为。
本教程将仅关注事务的传播机制行为。Spring事务的其他方面的细节,你可以参考其他的教程或Spring官方文档。
本教程所使用的完整代码可以在教程的下方下载。我们将仅显示Spring中帮助大家了解事务传播机制相关部分。
完整的源代码使用Hibernate实现持久层(Spring使用Hibernate的事务示例)。
2. REQUIRED行为
Spring的REQUIRED行为意味着如果在当前bean方法执行的上下文中已存在打开的事务,则使用该事务;如果没有已存在的事务,则Spring容器会创建新的事务并使用它。如果多个方法均配置为REQUIRED且调用为嵌套调用,那么它们会被划分为多个逻辑的事务,但在底层使用相同物理事务。简单来说,这意味着如果内层的方法引起了事务回滚,则外部的方法调用事务也会失败同时回滚。让我们看看一个示例:
外部Bean
[email protected]
02private TestDAO testDAO;
03
[email protected]
05private InnerBean innerBean;
06
[email protected]
[email protected](propagation=Propagation.REQUIRED)
09public void testRequired(User user) {
10 testDAO.insertUser(user);
11 try{
12 innerBean.testRequired();
13 } catch(RuntimeException e){
14 // handle exception
15 }
16}
内部Bean
[email protected]
[email protected](propagation=Propagation.REQUIRED)
3public void testRequired() {
4 throw new RuntimeException("Rollback this transaction!");
5}
注意内部bean的方法使用了REQUIRED进行了注解并抛出了RuntimeException。这意味着它将于外部bean使用相同的事务,因此外部事务在提交时将失败并同样进行回滚操作。
注意:默认情况下,只有非受检异常(unchecked exception),像RuntimeException,会将事务的状态设置为回滚。如果你希望受检异常(checked exception)也可以将事务状态设置为回滚,你必须设置它们,但此内部不包含在本教程中。
注意2:当使用声明式事务时(也就是通过使用注解形式),如果在相同的bean中直接调用方法(自己调用自己的方法),@Transactional注解将被容器忽略。如果你希望启用自身方法调用的事务管理,你必须使用aspectj来配置事务,但是该内容不包含在本教程中。
3. REQUIRES_NEW行为
REQUIRES_NEW行为意味着容器将总会创建新的物理的事务。换句话说,内部的事务可以独立于外部事务而提交或回滚事务,也就是说外部的事务将不受内部事务的结果影响:它们将返回不同的物理事务。.
外部 bean
[email protected]
02private TestDAO testDAO;
03
[email protected]
05private InnerBean innerBean;
06
[email protected]
[email protected](propagation=Propagation.REQUIRED)
09public void testRequiresNew(User user) {
10 testDAO.insertUser(user);
11 try{
12 innerBean.testRequiresNew();
13 } catch(RuntimeException e){
14 // handle exception
15 }
16} 内部 bean
[email protected]
[email protected](propagation=Propagation.REQUIRES_NEW)
3public void testRequiresNew() {
4 throw new RuntimeException("Rollback this transaction!");
5}内部方法使用REQUIREDS_NEW进行注解,并抛出RuntimeException,因此它的事务会回滚但是不会影响到外部的事务。外部事务在内部事务启动时将被挂起然后在内部事务处理完毕后恢复。它们独立的进行处理因此外部的事务也会成功的提交。
4. NETSTED行为
NESTED行为使用相同的物理事务但是在嵌套调用时设置了保留点(savepoint),因此内部的事务可以独立于外部事务回滚而不影响外部事务。这个可能与JDBC的savepoint比较类似,因此该行为需要与Spring的JDBC管理的事务一起使用(Spring JDBC 事务例子).
5. MANDATORY行为
MANDATORY行为要求执行该方法时,必须有一个已存在且打开的事务。如果没有已存在的事务,容器会抛出异常。
6. NEVER行为
NEVER行为要求执行该方法时,不能有已存在的事务。如果事务已存在,那么容器将会抛出异常。
7. NOT_SUPPORTED行为
NOT_SUPPORTED行为标示在执行方法时,将忽略事务。如果已存在打开的事务,则该事务会被挂起。
8. SUPPORTS行为
SUPPORTS行为标示在执行方法时,如果存在事务,则在事务范围执行,如果不存在,则不以事务方式执行。
9. 完整的笔记源码
本页尾有完整的代码下载。下面是 MySQL 建表语句:
MySQL 建表语句
1CREATE TABLE USER (
2 ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
3 USERNAME VARCHAR (32) NOT NULL,
4 NAME VARCHAR (64) NOT NULL,
5 UNIQUE (USERNAME)
6);
下载本教程源码
下载链接: spring-transaction-propagation-tutorial.zip