Spring也提供了声明式事务管理。这是通过Spring AOP实现的。
Spring 中进行事务管理的通常方式是利用AOP(面向切片编程)的方式,为普通java类封装事务控制,它是通过动态代理实现的,
由于接口是延迟实例化的, spring在这段时间内通过拦截器,加载事务切片。
通常通过TransactionProxyFactoryBean设置Spring事务代理。我们需要一个目标对象包装在事务代理中。
这个目标对象一般是一个普通Java对象的bean。当我们定义TransactionProxyFactoryBean时,
必须提供一个相关的 PlatformTransactionManager的引用和事务属性。 事务属性含有上面描述的事务定义。
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">★★1
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">★★2
<property name="transactionManager">★★3
<ref bean="transactionManager" />
</property>
<property name="target">★★4
<ref local="userDAO" />
</property>
<property name="transactionAttributes">★★5
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save">PROPAGATION_REQUIRED</prop>
<prop key="write">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean name="/regedit" class="action.RegeditAction" scope="request">
<property name="regedit">
<ref bean="userDAOProxy"/>★★6
</property>
</bean>
说明:★★1:是事务的消息类,属性值是sessionFactory,此类的实例会被作为参数传给★★3
★★2:TransactionProxyFactoryBean设置Spring事务代理
★★4:目标属性,是对具体的Bean进行事务处理,这里的id为"userDAOProxy"就是对"userDAO"的代理后的Bean引用。★★6就是对
声明式事务后的"userDAO"Bean进行的注入。
★★5:这里的transactionAttributes属性定义在 org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource
中的属性格式来设置。这个包括通配符的方法名称映射是很直观的。注意 get*的映射的值包括回滚规则。表示对get开头的方法进行事务处理。
但指定的方法中只要产生异常,事务将会自动回滚。
可以用逗号分隔定义多个回滚规则:
PROPAGATION_REQUIRED表示当前方法必须运行在一个事务环境中。如果一个现有的事务在运行,该方法则运行在这个事务中,
否则就要开始一个新的事务。
PROPAGATION_MANDATORY表示当前方法必须运行在一个事务环境中,否则抛出异常。
PROPAGATION_NEVER表示当前方法不能运行在一个事务环境中,否则抛出异常。
PROPAGATION_REQUIRES_NEW表示当前方法必须运行在自己的事务里面。
PROPAGATION_SUPPORTS表示当前方法不需要事务处理的环境,但这个方法在事务处理的环境中时,也不会报异常。
一般来讲,我们将业务逻辑层的方法设置为 "PROPAGATION_REQUIRED" ,readOnly表示此方法中只能做查询,不能对数据的修改。
然而,数据的查询是不需要事务的,所以,readOnly在这里没有实际的意义。
==========================================
下面提供一段完整的Spring的配置:
//***************链接数据库的配置********************
<bean id="database"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.microsoft.jdbc.sqlserver.SQLServerDriver">
</property>
<property name="url"
value="jdbc:microsoft:sqlserver://localhost:1433">
</property>
<property name="username" value="sa"></property>
</bean>
//***************session工厂的配置********************
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="database" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.SQLServerDialect
</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>po/Users.hbm.xml</value></list>
</property>
</bean>
//***************对Action进行配置(注意这里对"regedit"的注入,用的是声明式后的逻辑层的Bean)
<bean name="/regedit" class="action.RegeditAction" scope="request">
<property name="regedit">
<ref bean="userserviceproxy"/>
</property>
</bean>
//***************业务逻辑Bean的配置(要进行事务)********************
<bean id="regedit" class="service.RegeditImpl" >
<property name="dao">
<ref bean="regeditdao"/>
</property>
</bean>
//***************Dao的配置********************
<bean id="regeditdao" class="dao.UserDAOImpl">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
//***************声明式事务处理的配置********************
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userserviceproxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="regedit" /> //***************对应要进行声明式事务处理的Bean********************
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="regedit">PROPAGATION_REQUIRED</prop>
<prop key="write">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
========================================================================================
声明式事务处理的另一种配置方法
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<bean id="userserviceproxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">★★1
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="regedit">PROPAGATION_REQUIRED</prop>
<prop key="write">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
<bean id="fwxxbiz" parent="userserviceproxy">★★2
<property name="target" ref="regedit">
</bean>
<bean id="fwxxbiz2" parent="userserviceproxy">
<property name="target" ref="regedit2">
</bean>
... ... ...
说明:
这段配置与上面的这段配置基本上是相同的,唯一的区别是在配置TransactionProxyFactoryBean是没有指定具体的target属性,也就是
没有指定具体的Bean要进行事务处理,而是定义了abstract属性,看★★1,有这种配置的表明,此Bean不能产生实例对象。
而在★★2时,指定了父类Bean,并且填充了target属性。这样的配置的好处是,可以更灵活的指定对哪些Bean进行事务处理。