您的位置:首页 > 编程语言 > Java开发

spring 比较实用的事物管理

2009-06-23 10:08 337 查看
事物管理:这个有点抽象,书面表达是这样的:

为了完成对数据的操作,企业应用经常要求并发访问在多个构件之间共享的数据。这些应用在下列条件下应该维护数据的完整性(由应用的商务规则来定义):

分布式访问一个单独的数据资源,以及从一个单独的应用构件访问分布式资源。

在这种情况,可能要求在(分布式)资源上的一组操作被当作一个工作单元(unit)。在一个工作单元中, 操作的所有部分一起成功或失败并恢复。在下面的情况下这个问题更加复杂:

通过一组分布式的、访问多个资源的数据的构件实现一个工作单元,和/或部分操作是被顺序执行的或在要求协调和/或同步的并行线程中。

在所有情况下, 都要求应用维护一个工作单元的成功或失败。在失败的情况下,所有资源要把数据状态返回到以前的状态

(比如说,工作单元开始前的状态)。

事务的概念和和事务管理器(或者一个事务处理服务)在一个工作单元中的维护数据完整性,这就简化了这样的企业级别分布式应用的构造。

一个事务是有下列属性的一个工作单元:

原子性(ATOMICITY):

一个事务要被完全的无二义性的做完或撤消。在任何操作出现一个错误的情况下,构成事务的所有操作的效果必须被撤消,数据应被回滚到以前的状态。

一致性(CONSISTENCY):

一个事务应该保护所有定义在数据上的不变的属性(例如完整性约束)。在完成了一个成功的事务时,数据应处于一致的状态。换句话说,一个事务应该把系统从一个一致-状态转换到另一个一致状态。举个例子,在关系数据库的情况下,

一个一致的事务将保护定义在数据上的所有完整性约束。

隔离性(ISOLATION):

在同一个环境中可能有多个事务并发执行,而每个事务都应表现为独立执行。串行的执行一系列事务的效果应该同于并发的执行它们。这要求两件事:

在一个事务执行过程中,数据的中间的(可能不一致)状态不应该被暴露给所有的其他事务。

两个并发的事务应该不能操作同一项数据。数据库管理系统通常使用锁来实现这个特征。

持久性(DURABILITY):

一个被完成的事务的效果应该是持久的。

说的狭隘一点:就是你做你的事,我做我的事,但对事务的基本特征却没什么改变。比如说是一工具箱,我借钳子,你也借钳子,但我时间上比你早那么一点点,我用完了再给你,给你的还是一钳子,而不是钣手,而且你用的时候,东西也没坏。

公共的东西就是要保护好,大家都要用的。

这里我就说说要常用的spring的事务管理。

spring 有声明式,也有编码式的。编码的开发我是很少用

就说说声明的吧

。

这个要用到一个概念叫AOP(Aspect Oriented Programming).说白了就是在你的程序外面包层东西,让他符合这个事务的特性。

Spring也提供声明式事务管理。这是通过AOP实现的。大多数Spring用户选择声明式事务管理,这是最少影响应用代码的选择,因而这是和非侵入性的轻量级容器的观念是一致的。

1)通常通过TransactionProxyFactoryBean设置Spring事务代理。需要一个目标对象包装在事务代理中。这个目标对象一般是一个普通Javabean。当我们定义TransactionProxyFactoryBean时,必须提供一个相关的PlatformTransactionManager的引用和事务属性。事务属性含有事务定义。例如:

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory"/>

</bean>

这玩艺就是相关的 PlatformTransactionManager的引用和事务属性。

然后主体到了:

<bean id="transactionService"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

<property name="transactionManager">

<ref local="transactionManager"/>

</property>

<property name="target">

<ref local="transactionServiceControl"/>

</property>

<property name="transactionAttributes">

<props>

<prop key=”insert*”>PROPAGATION_REQUIRED,-MyCheckedException</prop>

<prop key=”update*”>PROPAGATION_REQUIRED</prop>

<prop key=”*”>PROPAGATION_REQUIRED,readOnly</prop>

</props>

</property>

</bean>

事务代理会实现目标对象的接口:这里是属性名是target的引用。id是transactionServiceControl。(使用CGLIB也可以实现具体类的代理。只要设置proxyTargetClass属性为true即可。如果目标对象没有实现任何接口,这将自动设置该属性为true。通常,我们希望面向接口编程。)使用proxyInterfaces属性来限定事务代理来代理指定接口也是可以。也可以通过从org.springframework.aop.framework.ProxyConfig继承或所有AOP代理工厂共享的属性来定制TransactionProxyFactoryBean行为。

然后,说说属性名是transactionAttributes意义:

这里的transactionAttributes属性是定义在org.springframework.transaction.interceptor.NameMathTransactionAttributeSource中的属性格式设置。这个包括通配符的方法名称映射是很直观的,如”insert*”。注意insert*的映射的值包括回滚规则。”-MyCheckException”指定如果方法抛出MyCheckException或它的子类,事务会自动回滚。可以用逗号分隔多个回滚规则。“-”前缀强制回滚,“+”前缀指定提交(这允许即使抛出unchecked异常时也可以提交事务)。“PROPAGATION_REQUIRED”指定事务传播范围。

TransactionProxyFactoryBean允许你通过“preInterceptors”和“postInterceptors”属性设置前或后的拦截操作。可以设置任意数量的前和后通过,它们的类型可以是Advistor(切入点),MethodInterceptor或被当前Spring配置支持的通知类型。例如:ThrowAdvice,AfterReturningAdvice或BeforeAdvice。这些通知必须支持实例共享模式。如果你需要高级AOP特性操作事务,通过org.springframework.aop.framework.ProxyFactoryBean,而不是TransactionProxyFactory实用代理创建者。

-----------------------------------------------------------------------------------------

这个是简单的,对每一个逻辑,也就是代码中的action来进行处理。这样做的话,可能最后变成配置地狱,此时可以考虑使用自动事务代理。

根据spring的BeanName来管理自动代理可以这样做:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="dataSource"

class="org.apache.commons.dbcp.BasicDataSource">

<property name="driverClassName">

<value>com.mysql.jdbc.Driver</value>

</property>

<property name="url">

<value>jdbc:mysql://localhost:3306/myuser</value>

</property>

<property name="username">

<value>lighter</value>

</property>

<property name="password">

<value>12345</value>

</property>

</bean>

<bean id="sessionFactory"

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">

org.hibernate.dialect.MySQLDialect

</prop>

<prop key="hibernate.show_sql">true</prop>

</props>

</property>

<property name="mappingResources">

<list>

<value>org/mmc/dao/domain/User.hbm.xml</value>

</list>

</property>

</bean>

<!-- 配置Hibernate的事务管理器 -->

<bean id="transactionManager"

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

<property name="sessionFactory" ref="sessionFactory" />

</bean>

<!-- 定义事务拦截器bean -->

<bean id="transactionInterceptor"

class="org.springframework.transaction.interceptor.TransactionInterceptor">

<property name="transactionManager" ref="transactionManager" />

<property name="transactionAttributes">

<props>

<prop key="insert*">PROPAGATION_REQUIRED</prop>

<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>

<prop key="*">PROPAGATION_REQUIRED</prop>

</props>

</property>

</bean>

<!-- 定义BeanNameAutoProxyCreator-->

<bean

class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

<property name="beanNames">

<!-- 所有名字以DAO,Service结尾的bean,将由该"bean后处理器"为其创建事务代理;实际上应该在业务层进行事务管理,这里只是举一个简单例子 -->

<value>*DAO,*Service</value>

</property>

<!--  下面定义BeanNameAutoProxyCreator所需的事务拦截器-->

<property name="interceptorNames">

<list>

<!-- 可以增加其他的拦截器 -->

<value>transactionInterceptor</value>

</list>

</property>

</bean>

<!-- 举下面这一个例子:这时候,这一个bean已经有了事务管理,可以增加类似的bean -->

<bean id="searchUserDAO" class="org.mmc.dao.impl.SearchUserDAO">

<property name="sessionFactory" ref="sessionFactory" />

</bean>

</beans>

-----------------------------------------------------

下面再看一种也是常用的使用bean继承简化事务代理配置

<bean id="test1" class="test.TransactionTestImpl">

<property name="ds"><ref local="dataSource"/></property>

</bean>

<bean id="test2" class="test.TestImpl">

<property name="ds"><ref local="dataSource"/></property>

</bean>

<bean id="baseTxProxy" lazy-init="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">

<property name="transactionManager"><ref bean="transactionManager"/></property>

<property name="transactionAttributes">

<props>

<prop key="*">PROPAGATION_REQUIRED</prop>

</props>

</property>

</bean>

<bean id="testTrans1" parent="baseTxProxy">

<property name="target">

<ref local="test1"/>

</property>

</bean>

<bean id="testTrans2" parent="baseTxProxy">

<property name="target">

<ref local="test2"/>

</property>

</bean>

使用继承的方法,其配置文件是增量式的,不如采用上面所说的第一种方法简捷,精炼。

ok 就这么多,不知道说明白没有。呵呵
[code]http://www.douban.com/note/433877038/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: