Spring 事务
spring 事务
在spring中事务通过transactionDefinition接口来定义
具体的方法:
清单1. TransactionDefinition 接口中定义的主要方法
1
2
3
4
5
6
|
public interface TransactionDefinition{
int getIsolationLevel();
int getPropagationBehavior();
int getTimeout();
boolean isReadOnly();
}
|
事务的隔离级别:
transactionDefinition.isolation.default 默认隔离级别,通常这个值是transactionDefinition.isolation_read_commited.
transactionDefinition.isolation_read_uncommited 该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据,该级别不能防止脏读和不可重复读,因此该级别很少使用。
transactionDefinition.isolation_read_commited 该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别能防止脏读,这是大多数情况下使用的隔离级别。
transactionDefinition.isolatin_repertable_read 该隔离级别表示一个事务在整个过程中可以重复执行某个查询。并且每次返回的结果都是一样的。即使在多次查询中有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
transactionDefinition.isolation_serializable 所有的事务依次逐个执行。这样事务之间就完全不可能受干扰。也就是说,该级别可以防止脏读,不可重复读以及幻读。但这严重影响程序性能。通常情况下不能使用该隔离级别。
事务的传播行为
TransactionDefinition.propagation_required 如果当前存在事务,则加入该事务;如果d昂前没有事务,则新建一个事务。
TransactionDefinition.propagation_required_new 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.propagation_supports 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.propagation_not_supports 以非事务的方式运行,如果当前存在事务,则把事务挂起。
TransactionDefinition.propagation_never 以非事务的当时运行,如果当前存在事务,则抛异常。
TransactionDefinition.propagation_mandatory 如果当前存在事务,则加入该事务,如果没有事务,则抛异常。
TransactionDefinition.propagation_nested 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于transactionDefinition.propagation_required
事务超时
指一个事务所允许执行的最长时间,如果超过该时间但事务还没有完成,则自动回滚事务。在TransactionDefinition中以int的值来表示超时时间,单位是秒。
事务的只读属性
对事务性资源进行只读操作或者读写操作。所谓事务性资源是指那些被事务管理的资源,比如数据源。如果确定进行只读操作。那我们那事务标记只读操作。以提高事务处理的性能。
在transactionDefinition中以boolean类型来表示该事务是否只读。
事务的回滚规则。
通常情况下事务中抛出未检出异常(继承自runtimeException),则默认回滚事务。如果没有抛异常或者抛已检查的异常都会提交事务。
spring事务管理api
1.transactionDefinition
包含事务的静态属性,事务的传播行为,超时时间等。spring提供了默认的实现类DefaultTransactionDefinition,该类使用绝大数情况,如果不能满足需求,可以通过实现TransactionDefinition接口。
2.platfromTransactionManager
清单2. PlatformTransactionManager 接口中定义的主要方法
1
2
3
4
5
6
|
Public interface PlatformTransactionManager{
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status)throws TransactionException;
void rollback(TransactionStatus status)throws TransactionException;
}
|
platformTransactionManager主要的实现类:
- DataSourceTransactionManager:适用于使用JDBC和iBatis进行数据持久化操作的情况。
- HibernateTransactionManager:适用于使用Hibernate进行数据持久化操作的情况。
- JpaTransactionManager:适用于使用JPA进行数据持久化操作的情况。
TransactionStatus
transactionStatus 提供一个简单dee 控制事务执行和查询事务的状态的方法。
清单3. TransactionStatus 接口中定义的主要方法
1
2
3
4
5
|
public interface TransactionStatus{
boolean isNewTransaction();
void setRollbackOnly();
boolean isRollbackOnly();
}
|
编程式事务管理
需要在代码里beginTransaction() commit rollback 等相关方法。spring将这些事务操作交给了持久化框架来执行。
清单4. 基于底层 API 的事务管理示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionDefinition txDefinition;
private PlatformTransactionManager txManager;
......
public boolean transfer(Long fromId, Long toId, double amount) {
TransactionStatus txStatus = txManager.getTransaction(txDefinition);
boolean result = false;
try {
result = bankDao.transfer(fromId, toId, amount);
txManager.commit(txStatus);
} catch (Exception e) {
result = false;
txManager.rollback(txStatus);
System.out.println("Transfer Error!");
}
return result;
}
}
|
相应的配置文件如清单5所示:
清单5. 基于底层API的事务管理示例配置文件
1
2
3
4
5
6
7
8
9
|
<bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="txManager" ref="transactionManager"/>
<property name="txDefinition">
<bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
</property>
</bean>
|
基于 TransactionTemplate 的编程式事务管理
清单6. 基于 TransactionTemplate 的事务管理示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionTemplate transactionTemplate;
......
public boolean transfer(final Long fromId, final Long toId, final double amount) {
return (Boolean) transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus status) {
Object result;
try {
result = bankDao.transfer(fromId, toId, amount);
} catch (Exception e) {
status.setRollbackOnly();
result = false;
System.out.println("Transfer Error!");
}
return result;
}
});
}
}
|
相应的XML配置如下:
清单 7. 基于 TransactionTemplate 的事务管理示例配置文件
1
2
3
4
5
|
<bean id="bankService"
class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>
|
声明式事务管理
基于 TransactionInter... 的声明式事务管理
最初,Spring 提供了 TransactionInterceptor 类来实施声明式事务管理功能。先看清单8的配置文件:
清单 8. 基于 TransactionInterceptor 的事务管理示例配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<beans...>
......
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"/>
</list>
</property>
</bean>
......
</beans>
|
基于 TransactionProxy... 的声明式事务管理
前面的声明式事务虽然好,但是却存在一个非常恼人的问题:配置文件太多。我们必须针对每一个目标对象配置一个 ProxyFactoryBean;另外,虽然可以通过父子 Bean 的方式来复用 TransactionInterceptor 的配置,但是实际的复用几率也不高;这样,加上目标对象本身,每一个业务类可能需要对应三个 <bean/> 配置,随着业务类的增多,配置文件将会变得越来越庞大,管理配置文件又成了问题。
为了缓解这个问题,Spring 为我们提供了 TransactionProxyFactoryBean,用于将TransactionInterceptor 和 ProxyFactoryBean 的配置合二为一。如清单9所示:
清单9. 基于 TransactionProxyFactoryBean 的事务管理示例配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<beans......>
......
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.classic.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
......
</beans>
|
基于 <tx> 命名空间的声明式事务管理
前面两种声明式事务配置方式奠定了 Spring 声明式事务管理的基石。在此基础上,Spring 2.x 引入了 <tx> 命名空间,结合使用 <aop> 命名空间,带给开发人员配置声明式事务的全新体验,配置变得更加简单和灵活。另外,得益于 <aop> 命名空间的切点表达式支持,声明式事务也变得更加强大。
如清单10所示:
清单10. 基于 <tx> 的事务管理示例配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<beans......>
......
<bean id="bankService"
class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<tx:advice id="bankAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))"/>
<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
......
</beans>
|
如果默认的事务属性就能满足要求,那么代码简化为如清单 11 所示:
清单 11. 简化后的基于 <tx> 的事务管理示例配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<beans......>
......
<bean id="bankService"
class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<tx:advice id="bankAdvice" transaction-manager="transactionManager">
<aop:config>
<aop:pointcut id="bankPointcut" expression="execution(**.transfer(..))"/>
<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
......
</beans>
|
基于 @Transactional 的声明式事务管理
除了基于命名空间的事务配置方式,Spring 2.x 还引入了基于 Annotation 的方式,具体主要涉及@Transactional 标注。@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如清单12所示:
清单12. 基于 @Transactional 的事务管理示例配置文件
1
2
3
4
|
@Transactional(propagation = Propagation.REQUIRED)
public boolean transfer(Long fromId, Long toId, double amount) {
return bankDao.transfer(fromId, toId, amount);
}
|
Spring 使用 BeanPostProcessor 来处理 Bean 中的标注,因此我们需要在配置文件中作如下声明来激活该后处理 Bean,如清单13所示:
清单13. 启用后处理Bean的配置
1
|
<tx:annotation-driven transaction-manager="transactionManager"/>
|
与前面相似,transaction-manager 属性的默认值是 transactionManager,如果事务管理器 Bean 的名字即为该值,则可以省略该属性。
虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 小组建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
基于 <tx> 命名空间和基于 @Transactional 的事务声明方式各有优缺点。基于 <tx> 的方式,其优点是与切点表达式结合,功能强大。利用切点表达式,一个配置可以匹配多个方法,而基于 @Transactional 的方式必须在每一个需要使用事务的方法或者类上用 @Transactional 标注,尽管可能大多数事务的规则是一致的,但是对 @Transactional 而言,也无法重用,必须逐个指定。另一方面,基于 @Transactional 的方式使用起来非常简单明了,没有学习成本。开发人员可以根据需要,任选其中一种使用,甚至也可以根据需要混合使用这两种方式。
如果不是对遗留代码进行维护,则不建议再使用基于 TransactionInterceptor 以及基于TransactionProxyFactoryBean 的声明式事务管理方式,但是,学习这两种方式非常有利于对底层实现的理解。
每次学习都是在走人生路