本文介绍了Spring对事物管理的两种方式,即编程式事物和声明式事物。
一.认识事物
事物是以可控制的方式限定程序对数据资源进行访问的一组操作;它的目的是为了保证程序运行中数据资源的正确性和完整性,为了达到这个目的,事物拥有以下四个属性:
1.原子性:原子性要求事物所包含的这一组操作是一个不可分割的整体,要么这组操作全部成功,要么其中一个失败,即整个事物失败;
2.一致性:一致性要求事物的这一组操作完成之后,必须要保证数据资源前后一致的状态;比如我现在有一个账户中有10万元,在一次交易中为某个订单付款1万元,则我的账户还剩9万元,加上订单所属的商家账户增加的1万元,整个系统有有一个10万元的平衡,如果我付了款后账户不是9万元,则没有保证一致性;
3.隔离性:隔离性表示了各个事物之间互相影响的程度,或称之为隔离度更加准确;
4.持久性:持久性是说,一旦事物提交,则数据已经持久化,就是说已经写到硬盘(或其他设备)上了,不能逆转了;
二.事物的隔离级别
通常情况下,事物哟以下四种隔离级别,即上面所说的隔离度:
a.Read Uncommitted ,该级别下一个事物可以读取另一个事物没有提交的数据;该级别不能防止脏读和不可重复读;
b.Read Commited,该级别下,在同一个事务只能看见已经提交事务所做的改变;该级别可以防止脏读;
c.Repeatable Read ,他保证了在同一个事物中对同一笔数据的读取结果是相同的,不管其他事物是否更新或提交;该级别可以防止脏读和不可重复读;
d.Serializable,该级别对事物进行排序,使每一个事物都安顺序执行,因此是最为安全的各级级别,但性能也最差;该级别可以防止脏读、不可重复读以及幻读。
在 Spring 中,事务是通过 TransactionDefinition 接口来定义的,该接口包含与事务属性有关的方法。
public interface TransactionDefinition{
int getIsolationLevel();
int getPropagationBehavior();
int getTimeout();
boolean isReadOnly();
}
TransactionDefinition 接口中定义了五个表示隔离级别的常量:ISOLATION_DEFAULT、ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE,如果设为ISOLATION_DEFAULT,则表示采用底层数据库的默认隔离级别。
三.隔离级别的比较
四种隔离级别各有优劣,一般数据库的默认级别为Read Commited。不同的隔离级别对系统的并发性及数据的完整性会造成不同程度的影响,可以说隔离级别与系统的并发成反比,与数据的一致性成正比。但总的来说,对数据一致性的考虑要优于对系统性能的考虑。
隔离级别的强度排序:Serializable > Repeatable Read > Read Commited > Read Uncommitted
四.Spring 的事物传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
五.Spring事物管理
a.编程式事物
简单的说就是通过Spring在程序中手动地管理实务的执行。编程式事物的管理通过PlatformTransactionManager、TransactionDefinition 和 TransactionStatus三个核心接口操作。
b.声明式事物
声明式事物是基于Spring AOP 的,主要是在方法前后进行拦截,在方法开始时加入事物,在方法结束时根据执行情况进行事物的提交或回滚,这样做的好处是,将事物代码分离了出来,使开发人员只关注于业务逻辑,不仅简化了代码,提高了可读性,也提高了可维护性。但事物的细粒度只能精确到方法级别,无法像编程式事物那样精确到块的级别。
下面是几种常用的事物配置方法:
1.基于TransactionProxyFactoryBean的代理方式:
<!-- 定义事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="txProxyTemplate" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 这是一个自动代理,用来在被代理的bean 中指定的方法上加上事物
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="txProxyTemplate" />
</list>
</property>
<property name="beanNames">
<list>
<value>*Manager</value>
</list>
</property>
</bean>
这里通过代理的方法自动为所有以manager为后缀的Bean加上了事物。
2.基于<tx>命名空间的事物管理的方式:
<!-- 定义事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置事务传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="search*" propagation="REQUIRED" read-only="true"/>
<tx:method name="save*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置参与事务的类 -->
<aop:config>
<aop:pointcut id="interceptorPointCuts" expression="execution(* com.demo.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />
</aop:config>
小提示:expression="execution(* com.test.testAda.test.model.service.*.*(..))",其中第一个*代表返回值,第二*代表service下子包,第三个*代表方法名,“(..)”代表方法参数。
3.基于@Transactional注解的方式
下面的实例来自于真实项目
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 使用annotation定义事务 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
在类中需要加上@Transactional
@Transactional
public class CategoryManager{}
如果是只读的,在方法加上readonly属性即可
@Transactional(readOnly = true)
public Object get(Long id) {
...
}
六.结语
本文对spring的事物做了一个浅显的解析,包括对事物的认识及Spring事物的配置。若有不对的地方,还请大家多多指点。
注:本文参考http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/index.html