Spring 事务 (二) Spring 声明式事务 配置
Spring 事务 (二) Spring 声明式事务 配置
2. Spring 声明式事务 配置
由Spring 事务 (一)知道,Spring事务基本概念中,最重要的是
PlatformTransactionManager,它的
TransactionStatus getTransaction(TransactionDefinition definition)
方法根据一个TransactionDefinition生成TransactionStatus.
这样可知,配置事务,首先需要配置一个PlatformTransactionManager信息,
然后需要配置 TransactionDefinition信息.而TransactionStatus是返回的值,
根据前面两个配置由TransactionStatus对象获取相应的配置信息.
所以配置时,主要配置PlatformTransactionManager,TransactionDefinition.
Spring的事务功能由事务代理完成.
一般的流程是:
先编写业务接口,
然后编写一个业务接口的实现类,并配置为bean(targetBean),
再配置一个TransactionProxyFactoryBean,得到一个代理bean(代理targetBean),
然后客户端代码中,通过代理bean的id来调用getBean方法,得到TransactionProxyFactoryBean配置的bean.
配置这个代理bean需要传入一个事务管理器(PlatformTransactionManager),一个目标bean(targetBean),
并指定事务代理的事务属性.
上述配置TransactionProxyFactoryBean的方式为显示的,即配置一个targetBean,和一个有事务行为的代理bean,
实际上配置了两个bean,而原来的targetBean是不直接使用的,假如代码中不小心使用了targetBean,则会产生问题.
因此Spring还提供了一种基于tx命名空间的方式来配置事务代理bean,这种配置类似于AOP配置,只配置一个bean,
当根据bean id使用getBean()获取bean实例时,Spring容器自动提供事务代理bean的实例.
http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/section5.html
上面链接中,还讨论了使用拦截器实现的事务(非事务代理bean方式),供参考.
2.1 PlatformTransactionManager配置
PlatformTransactionManager配置,根据不同数据源的使用,以及是局部事务还是全局事务 来分类,
主要有下面几种配置方式:
2.1.1 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类
<!-- 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类 --> <!-- DataSource配置,可配置为c3p0连接池等,这里省略 --> <bean id="dataSource" ...>...</bean> <bean id="transactionManager" class="org.springframework.jdbc.datasouce.DataSouceTransactionManager"> <!-- 配置DataSourceTransactionManager时,需要依赖注入DataSource的引用 --> <property name="dataSource" ref="dataSource"/> </bean>
2.1.2 采用全局事务的特定实现
<!-- 采用全局事务的特定实现 --> <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
上面配置,无需指定datasource. 全局事务有JTA实现(比如有的容器weblogic等实现JTA,
也有专门的开源框架实现JTA,如JOTM)
2.1.3 使用Hibernate的配置
<!-- 使用Hibernate的配置 --> <!-- DataSource配置,可配置为c3p0连接池等,这里省略 --> <bean id="dataSource" ...>...</bean> <!-- Hibernate的SessionFactory配置,这里省略 --> <bean id="sessionFactory" ...>...</bean> <bean id="transactionManager" <!-- 针对Hibernate的特定实现类 --> class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <!-- 配置Hibernate时,需要依赖注入SessionFactory的引用 --> <property name="sessionFactory" ref="sessionFactory"/> </bean>
3 配置 TransactionProxyFactoryBean
3.1 配置一个targetBean(业务逻辑bean),和一个有事务行为的代理bean
<!-- 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类 --> <!-- DataSource配置,可配置为c3p0连接池等,这里省略 --> <bean id="dataSource" ...>...</bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 配置DataSourceTransactionManager时,需要依赖注入DataSource的引用 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 一个业务逻辑bean --> <bean id="newsDao" class="xxx.xxx.NewsDao" > <property name="ds" ref="dataSource" /> </bean> <!-- 为业务逻辑bean配置事务代理 --> <bean id="newsDaoTran" class="org.springframework.transaction.intereptor.TransactionProxyFactoryBean"> <!-- 注入事务管理器 --> <property name="transactionManager" ref="transactionManager" /> <!-- 指定被代理的目标bean --> <property name="target" ref="newDao" /> <!-- 指定事务属性 --> <property name="transactionAttributes"> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean>
上面transactionAttributes标示注入的是一个properties类型的属性.
key表示方面名称,可以使用通配符,
value表示事务规则:
指定事务属性的取值有较复杂的规则,具体的书写规则如下:
传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常]
只有传播行为是必须指定的,其他的可以省略(取默认值)
传播行为是唯一必须设置的属性,其他都可以忽略,Spring为我们提供了合理的默认值。
传播行为的取值必须以“PROPAGATION_”开头,
具体包括:
PROPAGATION_MANDATORY、
PROPAGATION_NESTED、
PROPAGATION_NEVER、
PROPAGATION_NOT_SUPPORTED、
PROPAGATION_REQUIRED、
PROPAGATION_REQUIRES_NEW、
PROPAGATION_SUPPORTS,共七种取值。
隔离级别的取值必须以“ISOLATION_”开头,
具体包括:
ISOLATION_DEFAULT、
ISOLATION_READ_COMMITTED、
ISOLATION_READ_UNCOMMITTED、
ISOLATION_REPEATABLE_READ、
ISOLATION_SERIALIZABLE,共五种取值。
如果事务是只读的,那么我们可以指定只读属性,
使用“readOnly”指定。否则我们不需要设置该属性。
超时属性的取值必须以“TIMEOUT_”开头,
后面跟一个int类型的值,表示超时时间,单位是秒。
不影响提交的异常是指,即使事务中抛出了这些类型的异常,
事务任然正常提交。必须在每一个异常的名字前面加上“+”。
异常的名字可以是类名的一部分。比如“+RuntimeException”、“+tion”等等。
导致回滚的异常是指,当事务中抛出这些类型的异常时,事务将回滚。
必须在每一个异常的名字前面加上“-”。异常的名字可以是类名的全部或者部分,
比如“-RuntimeException”、“-tion”等等。
以下是两个示例:
<property name="*Service"> PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20, +AbcException,+DefException,-HijException </property>
以上表达式表示,针对所有方法名以 Service 结尾的方法,
使用 PROPAGATION_REQUIRED 事务传播行为,
事务的隔离级别是 ISOLATION_READ_COMMITTED,
超时时间为20秒,
当事务抛出 AbcException 或者 DefException 类型的异常,则仍然提交,
当抛出 HijException 类型的异常时必须回滚事务。
这里没有指定"readOnly",表示事务不是只读的。
<property name="test">PROPAGATION_REQUIRED,readOnly</property>
以上表达式表示,针对所有方法名为 test 的方法,
使用 PROPAGATION_REQUIRED 事务传播行为,
并且该事务是只读的。
除此之外,其他的属性均使用默认值。
比如,隔离级别和超时时间使用底层事务性资源的默认值,
并且当发生未检查异常,则回滚事务,
发生已检查异常则仍提交事务。
参考:
http://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/section5.html
3.2 基于tx命名空间的方式来配置事务代理bean
这种配置类似于AOP配置,只配置一个bean,
当根据bean id使用getBean()获取bean实例时,Spring容器自动提供事务代理bean的实例.
<?xml version="1.0" encoding="UTF-8"?> <!-- 需要使用这样的beans头,指定tx,aop的schema --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd" > <!-- 数据源使用JDBC数据源的局部事务,使用DataSourceTransactionManager类 --> <!-- DataSource配置,可配置为c3p0连接池等,这里省略 --> <bean id="dataSource" ...>...</bean> <bean id="transactionManager" class="org.springframework.jdbc.datasouce.DataSouceTransactionManager"> <!-- 配置DataSourceTransactionManager时,需要依赖注入DataSource的引用 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 一个业务逻辑bean --> <bean id="newsDao" class="xxx.xxx.NewsDao" > <property name="ds" ref="newsDao" /> </bean> <!-- 配置增强处理的bean(相当于切面类),也是Spring自动生成普通 业务逻辑bean(targetBean)的代理Bean.里面的tx:method配置每个方法的事务属性, name配置方法名,可使用通配符. --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置详细的事务语义 --> <tx:attributes> <!-- 表示get开头的方法是只读的 --> <tx:method name="get*" read-only="true" /> <!-- 其他方法使用默认的事务设置,事务传播方式也可以默认么? --> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- AOP元素配置 --> <aop:config> <!-- 配置一个切入点 xxx.xxx包下面所有已Imp1结尾的类的所有方法--> <aop:pointcut id="myPoint" expression="execution(* xxx.xxx.*Imp1.*(..))" /> <!-- 配置 (事务代理)切入点(aop:pointcut) 和 切面类(tx:advice),将二者关联起来 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint" /> </aop:config> </beans>
注:
aop:config中 aop:pointcut配置切入点,表名哪些方法将会被事务代理增强.
tx:advice 相当于配置一个切面类,并标明对符合条件的方法采用何种事务.
aop:config中aop:advisor将上述二者关联起来
<tx:attributes>的tx:method的
name属性是必须的,可以使用通配符,表示与改事务语义管理的方法名.
另外,还有属性:
propagation,isolation,timeout,read-only,rollbak-for,no-rallback-for.(P684)
附件中 classes12.jar是oracle的驱动包.
上一篇: Mybatis框架