Spring中的四种声明式事务的配置Spring容器中有两种思想很重要也就是我们常用的Ioc和Aop如果理解了这两种思想对于我们学习设计模式和编程有很大的帮助美国四人帮(GOF)写的设计模式中有很多都用到了Ioc的思想简单的说就是依赖注入的思想常见的一种情况如果一个类中要复用另外一个类中的功能时我们可能会首先想到继承如果你知道Ioc这种思想的话我想你不会用继承你会马上想到把要用到功能抽取出来在我们要用到的类中只需通过set方法简单的注入就可以了其实这里用到了对象的组合代替继承这样不仅避免了单一继承还很好的实现了松耦合同时也遵循了面向对象的编程的设计原则多用组合少用继承在这里对于Ioc和Aop这两种思想的好处我就不介绍了接下来我要说的是Spring中几种常见的事务配置是Aop和Ioc的充分体现
在说点题外话以前EJB在JEE中开发中可是大名鼎鼎的了就是因为EJB提供了很多服务而不需要我们去开发了其中用到最多的算是它提供的声明式事务了在Spring没有出现之前EJB在JEE开发中扮演着非常重要的角色同时也是很多项目失败的罪魁祸首其中的原因就是因为它是重量级强侵入性收费的框架需要昂贵的服务器支持在加上它的测试更是让人头痛而Spring恰恰与它相反Spring是一个轻量级的非侵入性的开源框架它提供的声明式事务的功能更是强大不需要容器的支持这一点吸引力很多人愿意放弃EJB而使用Spring让我们言归正传吧
以下两个bean的配置是下面要用到的
<! 定义事务管理器(声明式的事务) >
<bean id=transactionManager
class=orgspringframeworkormhibernateHibernateTransactionManager>
<property name=sessionFactory>
<ref local=sessionFactory />
</property>
</bean>
<! *******业务逻辑层(是对各个DAO层的正面封装)主要用到<<门面模式>>****** >
<bean id=fundService
class=comjackfundserviceserviceimplFundService>
<property name=operdao>
<ref bean=operatorDAO />
</property>
<property name=producedao>
<ref bean=fundProduceDAO />
</property>
<property name=customerdao>
<ref bean=customerDAO />
</property>
<property name=accountdao>
<ref bean=accountDAO />
</property>
<property name=fundaccountdao>
<ref bean=fundAccountDAO />
</property>
<property name=fundtransdao>
<ref bean=fundTransDAO />
</property>
</bean>
可能还有其他很多模块<bean id=fundService/>可能只是其中的模块
第一种配置声明式事务的方法如下也是我们最常用的方法了它适用于你的库表比较少的情况下
<bean id=fundServiceDAOProxy
class=orgspringframeworktransactioninterceptorTransactionProxyFactoryBean>
<! 配置事务管理器 >
<property name=transactionManager>
<ref bean=transactionManager />
</property>
<! 此属性指定目标类本省是否是代理的对象如果目标类没有实现任何类就设为true代表自己 >
<property name=proxyTargetClass>
<value>false</value>
</property>
<property name=proxyInterfaces>
<value>comjackfundserviceIFundService</value>
</property>
<! 目标bean >
<property name=target>
<ref bean=fundService />
</property>
<! 配置事务属性 >
<property name=transactionAttributes>
<props>
<prop key=delete*>PROPAGATION_REQUIRED</prop>
<prop key=add*>PROPAGATION_REQUIRED</prop>
<prop key=update*>PROPAGATION_REQUIRED</prop>
<prop key=save*>PROPAGATION_REQUIRED</prop>
<prop key=find*>PROPAGATION_REQUIREDreadOnly</prop>
</props>
</property>
</bean>
以下可能还有其他的xxxServiceDAOProxy大家可以看出针对每一个功能模块配置一个业务代理服务如果模块多大话就显得代码有点多了发现他们只是稍微一点不一样这时我们就应该想到继承的思想用第二种方法
第二种配置声明式事务的方法如下这种情况适合相对比较多的模块时使用
<! 利用继承的思想简化配置要把abstract=true >
<bean id=transactionBase
class=orgspringframeworktransactioninterceptorTransactionProxyFactoryBean
lazyinit=true abstract=true>
<! 配置事务管理器 >
<property name=transactionManager>
<ref bean=transactionManager />
</property>
<! 配置事务属性 >
<property name=transactionAttributes>
<props>
<prop key=delete*>PROPAGATION_REQUIRED</prop>
<prop key=add*>PROPAGATION_REQUIRED</prop>
<prop key=update*>PROPAGATION_REQUIRED</prop>
<prop key=save*>PROPAGATION_REQUIRED</prop>
<prop key=find*>PROPAGATION_REQUIREDreadOnly</prop>
</props>
</property>
</bean>
而具体的模块可以简单的这样配置只要指明它的parent(父类)就可以了父类一般把abstract=true因为在容器加载的时候不需要初始化等到用的时候再有它的子类调用的时候再去初始化
<bean id=fundServiceDAOProxy parent=transactionBase >
<property name=target>
<ref bean=fundService />
</property>
</bean>
这样配置的话如果有多个像fundService这样模块时可以少些很多重复的代码
第三种配置声明式事务的方法如下主要利用BeanNameAutoProxyCreator自动创建事务代理
<bean id=transactionInterceptor
class=orgspringframeworktransactioninterceptorTransactionInterceptor>
<property name=transactionManager>
<ref bean=transactionManager />
</property>
<! 配置事务属性 >
<property name=transactionAttributes>
<props>
<prop key=delete*>PROPAGATION_REQUIRED</prop>
<prop key=add*>PROPAGATION_REQUIRED</prop>
<prop key=update*>PROPAGATION_REQUIRED</prop>
<prop key=save*>PROPAGATION_REQUIRED</prop>
<prop key=find*>PROPAGATION_REQUIREDreadOnly</prop>
</props>
</property>
</bean>
<bean
class=orgspringframeworkaopframeworkautoproxyBeanNameAutoProxyCreator>
<property name=beanNames>
<list>
<value>fundService</value>
</list>
</property>
<property name=interceptorNames>
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
这种方法主要利用了拦截器的原理
前三种方法一般都必需指定具体的模块bean如果模块过多话比如一个大型的网站一般有几十个模块我们就得考虑用第四种的配置方式了自动创建事务代理的方式了
第四种配置声明式事务的方法如下 <bean id=transactionInterceptor
class=orgspringframeworktransactioninterceptorTransactionInterceptor>
<property name=transactionManager>
<ref bean=transactionManager />
</property>
<! 自动代理 >
<bean id=autoproxy
class=orgspringframeworkaopframeworkautoproxyBeanNameAutoProxyCreator>
<! 可以是Service或DAO层(最好是针对业务层*Service) >
<property name=beanNames>
<list>
<value>*Service</value>
</list>
</property>
<property name=interceptorNames>
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
自动代理还有一种用法就是结合正规表达式和advice使用
<bean id=transactionInterceptor
class=orgspringframeworktransactioninterceptorTransactionInterceptor>
<property name=transactionManager>
<ref bean=transactionManager />
</property>
<bean id=autoProxyCreator
class=orgspringframeworkaopframeworkautoproxyDefaultAdvisorAutoProxyCreator />
<bean id=regexpMethodPointcutAdvisor
class=orgspringframeworkaopsupportRegexpMethodPointcutAdvisor>
<property name=advice>
<ref bean=transactionInterceptor />
</property>
<property name=pattern>
<value>*</value>
</property>
</bean>
这个方法可以针对具体的模块进行拦截并进行事务处理在你的实际项目中你可以根据你的情况选用不同的方法