Spring中的Hibernate事务:
如果应用持久层是用Hibernate实现的,就会用到HibernateTransactionManager。在应用中使用下面所有的XML来声明它。
<bean id = "transactionManager" class = "org.springframework.orm.hibernate.HibernateTransactionManager">
<property name = " sessionFactory " >
<ref bean = "sessionFactory " />
</property>
</bean>
其中,sessionFactory 属性必须和一个Hibernate的SessionFactory 绑定。如下:
<!--定义一个hibernate 的SessionFactory -->
<bean id="sessionFactory " class="org.springframework.orm.hibernate3.LocalSessionFactory Bean">
<!-- 定义SessionFactory 必须注入数据库属性DataSource-->
<property name="dataSource">
<ref local="dataSource"/>
</property>
<!-- 在<list>中, 列出所有的PO 映射文件-->
<property name="mappingResources">
<list>
<value>Person.hbm.xml</value>
</list>
</property>
<!-- 定义hibernate的属性-->
<property name="hibernateProperties">
<props>
<!--此处用来定义hibernate 的SessionFactory 的属性:不同数据库连接启动时选择create , update , create-drop-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
HibernateTransactionManager把事务管理委托给一个从Hibernate session中取得的net.sf.hibernate.Transaction对象,当一个事务完成时,HibernateTransactionManager将调用Transaction对象的commit()方法。类似的,当一个事务失败时,Transaction对象的rollback()方法将被调用。
用BeanNameAutoProxyCreator 自动创建事务代理
下面介绍-种优秀的事务代理配置策略,采用这种配置策略,完全可以避免增量式配置,使所有的事务代理由系统自动创建。由于容器中的目标bean 自动消失,可避免需要使用嵌套bean 来保证目标bean 不可被访问。
这种配置方式依赖于Spring 提供的bean 后处理器,该后处理器用于为每个bean 自动创建代理,此处的代理不仅可以是事务代理,也可以是任意的代理,只需要有合适的拦截器即可。这些是AOP 框架的概念,笔者在此处不AOP 进行深入介绍。读者只需了解这种事务代理的配置方式即可。
下面是采用BeanNameAutoProxyCreator 配置事务代理的配置文件:
<?xml version="1.0" encoding="gb2312"?>
<!一Spring 配置文件的文件头,包含DTD 等信息-->
<lDOCTYPE beans PUBLIC "-IISPRINGIIDTD BEANIIEN"
''http://www. spr工ngfrarnework.org/dtd/spring-beans.dtd">
<beans>
<!- - 定义数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!一定义数据库驱动一>
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<!-- 定义数据库url-->
<property name="url"><value>jdbc:mysql://localhost:3306/spring</value></property>
<!-- 定义数据库用户名-->
<property name= "username" ><value>root</value></property>
<!-- 定义数据库密码-->
<property name="password"><value>32147</value></property>
</bean>
<!--定义一个hibernate 的SessionFactory -->
<bean id="sessionFactory " class="org.springframework.orm.hibernate3.LocalSessionFactory Bean">
<!-- 定义SessionFactory 必须注入数据库属性DataSource-->
<property name="dataSource">
<ref local="dataSource"/>
</property>
<!-- 在<list>中, 列出所有的PO 映射文件-->
<property name="mappingResources">
<list>
<value>Person.hbm.xml</value>
</list>
</property>
<!-- 定义hibernate的属性-->
<property name="hibernateProperties">
<props>
<!--此处用来定义hibernate 的SessionFactory 的属性:不同数据库连接启动时选择create , update , create-drop-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!--配置事务管理器 ,使用适用于Hibernate 的事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- HibernateTransactionManager bean 需要依赖注入一个SessionFactory bean 的引用-->
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<!-- 配置事务拦截器 -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<!-- 事务拦截器bean 需要依赖注入一个事务管理器-->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<!-- 下面定义事务传播属性-->
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!--定义BeanNameAutoProxyCreator ,该bean 是个bean 后处理器,无须被引用,因此没有id 属性。这个bean 后处理器,根据事务拦截器为目标bean 自动创建事务代理-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
<!-- 指定对满足哪些bean name 的bean 自动生成业务代理 -->
<property name="beanNames">
<!--下面是所有需要自动创建事务代理的bean-->
<list>
<value>customerDAO</value>
</list>
</property>
<!--下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
</beans>
TranscationInterceptor是一个事务拦截器bean,需要传入一个TransactionManager的引用。配置中使用Spring 依赖注入该属性,事务拦截器的事务属性通过transactionAttributes 来指定,该属性有props 子元素,并在配置文件中定义了三个事务传播规则。
所有以insert 开始的方法,都采用PROPAGATION_REQUIRED的事务传播规则。当程序抛出MyException异常及其子异常时,会自动回滚事务:所有以find 开头的方法,都采用PROPAGATION_REQUIRED事务传播规则,并且具有只读性;其他方法则采用PROPAGATION_REQUIRED的事务传播规则。BeanNameAutoProxyCreator是根据bean 名生成自动代理的代理创建器,该bean 通常需要接受两个参数:第一个是beanNames 属性,该属性用来设置哪些bean 需要自动生成代理,另一个属性是interceptorNames,该属性则指定事务拦截器,在自动创建事务代理时,系统会根据这些事务拦截器的属性来生成对应的事务代理。
为了让读者对这种配置方式有信息,可PersonDaoHibemate的save 方法进行简单修改,修改后的save 方法如下:
/**
*保存person 实例
* @param person 需要保存的Person 实例
*/
public void save(Person person)
{
getHibernateTemplate() .save(person);
//下面两行代码没有实际意义,仅仅为了引发数据库异常
DataSource ds = null;
DataSourceUtils.getConnection(ds);
在主程序中调用该save 方法,主程序调用save 方法的代码如下:
for(int i = 0 ; i < 10 ; i++ )
{
// 保存Person 实例
pdao.save(new Person(String.valueOf(i) , i + 10));
执行完主程序的该片段后,数据库不会插入任何记录。如果BeanNameAutoProxyCreator 的配置修改成如下格式:
<! --定义BeanNameAutoProxyCreator,该bean 是个bean 后处理器,无须被引用,因此没有id 属性这个bean 后处理器,根据事务拦截器为目标bean 自动创建事务代理-->
<bean c1ass="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--指定对满足哪些bean name 的bean 自动生成业务代理-->
<property name="beanNames">
<!--下面是所有需要自动创建事务代理的bean-->
<list>
<!-- <value>personDao</value> -->
</list>
<!一此处可增加其他需要自动创建事务代理的bean-->
</property>
<!-- 下面定义BeanNameAutoProxyCreator所需的事务拦截器-->
<property name="interceptorNames">
<list>
<value>transactionInterceptor</va1ue >
<!--此处可增加其他新的Interceptor -->
</list>
</property>
</bean>
注意配置文中beanNames属性的变化,将所有personDao项加注释 ,即不再为该bean生成事务代理。再次执行主程序,此时程序虽然抛出了数据库异常,但数据记录依然被插入数据库。
这种配置方式相当简洁,每次都增加了新的bean。如果需要该bean 的方法具有事务性,只需在BeanNameAutoProxyCreator 的beanNames 属性下作相应修改。该行告诉bean 后处理需要为哪个bean 生成事务代理。
注意:采用BeanNameAutoProxyCreator 配直事务代理时,无须为每个目标额外配直
多余的事务代理,可由系统自动为其创建事务代理。事实上,BeanNameAutoProxyCreator
并不是专用于创建事务代理,它可以根据配直的拦截器列表生成代理。在该系统中,只
指定了一个transactionInterceptor ,该拉截器是事务栏截器,由Spring 提供实现。该拦截
器也可以由用户提供,在后面的表现层组件中可以看到用户自定义的授权拦截器。