博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring声明性事务配置几种方式
阅读量:7222 次
发布时间:2019-06-29

本文共 10071 字,大约阅读时间需要 33 分钟。

hot3.png

 最初使用Spring是为了解决业务层的事务管理问题。原先用手写代码发起、结束/回滚事务的做法碰到粗心的开发者很容易导致连接池的资源耗尽。Spring的声明性事务管理功能无疑是一剂良方。本文说明几种常见的配置方式及各自的优缺点。
方法一:BeanNameAutoProxyCreator
优点:有大量bean声明性事务管理时使用该方法可以简化配置
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"
>
<beans>
    <description>
        Exploring spring Dependency Injection feature
    </description>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>
    <!-- Transaction Interceptor set up to do PROPOGATION_REQUIRED on all methods -->
    <bean id="matchAllTxInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
    <!-- One BeanNameAutoProxyCreator handles all beans where we want all methods to use
    PROPOGATION_REQUIRED -->
    <bean id="hibInterceptor"
        class="org.springframework.orm.hibernate.HibernateInterceptor">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>
    <bean id="autoProxyCreator"
        class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames">
            <list>
                <idref local="matchAllTxInterceptor"/>
                <idref bean="hibInterceptor"/>
            </list>
        </property>
        <property name="proxyTargetClass">
            <value>true</value>
        </property>
        <property name="beanNames">
            <list>
                <value>userDocumentManager</value>
            </list>
        </property>
    </bean>
    <bean id="docServerConfig" class="just.docserver.config.DocServerConfig" singleton="true">
        <property name="config"><value>docsrv.conf</value></property>
        <!-- contextPath is which url path the document server resides, KEEP it sync with actual deployment -->
        <property name="contextPath"><value>/axis</value></property>
    </bean>    
    <!--DAO classes definition begin-->
    <bean id="docDao" class="just.docserver.dal.daoimpl.doc.DocDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userFileDao" class="just.docserver.dal.daoimpl.doc.UserFileDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="docSettingDao" class="just.docserver.dal.daoimpl.doc.DocSettingDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userDocumentDao" class="just.docserver.dal.daoimpl.doc.UserDocumentDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
    </bean>    
    <!--DAO classes definition end-->
    
    <!--  Service definition begin -->
    <bean id="userDocumentManager"
        class="just.docserver.UserDocumentManagerImpl"
        singleton="true">
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userDocumentDao"><ref local="userDocumentDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
        <property name="docServerConfig"><ref local="docServerConfig"/></property>
    </bean>
    <!--  Service definition end -->
</beans>
方法二:TransactionProxyFactoryBean
优点:配置灵活
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"
>
<beans>
    <description>
        Exploring spring Dependency Injection feature
    </description>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>
    <bean id="docServerConfig" class="just.docserver.config.DocServerConfig" singleton="true">
        <property name="config"><value>docsrv.conf</value></property>
        <!-- contextPath is which url path the document server resides, KEEP it sync with actual deployment -->
        <property name="contextPath"><value>/axis</value></property>
    </bean>    
    <!--DAO classes definition begin-->
    <bean id="docDao" class="just.docserver.dal.daoimpl.doc.DocDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userFileDao" class="just.docserver.dal.daoimpl.doc.UserFileDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="docSettingDao" class="just.docserver.dal.daoimpl.doc.DocSettingDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userDocumentDao" class="just.docserver.dal.daoimpl.doc.UserDocumentDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
    </bean>    
    <!--DAO classes definition end-->
    
    <!--  Service definition begin -->
  <bean id="userDocumentManagerTarget" class="just.docserver.UserDocumentManagerImpl">
      <property name="docDao"><ref local="docDao"/></property>
      <property name="docSettingDao"><ref local="docSettingDao"/></property>
      <property name="userDocumentDao"><ref local="userDocumentDao"/></property>
      <property name="userFileDao"><ref local="userFileDao"/></property>
      <property name="docServerConfig"><ref local="docServerConfig"/></property>
  </bean>
    <bean id="userDocumentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager">
        <ref local="transactionManager"/>
      </property>  
      <property name="target">
        <ref local="userDocumentManagerTarget"/>
      </property>
      <property name="proxyInterfaces"><value>just.docserver.UserDocumentManager</value></property>
      <property name="transactionAttributes">
        <props>
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
      </property>
    </bean>    
    <!--  Service definition end -->
</beans>
但使用该方法配置时需要多配置一个xxxTarget的bean,该bean通常在应用用没有直接的用途,使得配置显得比较累赘。这一问题在高版本的spring中可以用嵌套的bean来解决。也就是将名为xxxTarget的bean直接写道被引用到的地方。按此方法,上例可以改成:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"
>
<beans>
    <description>
        Exploring spring Dependency Injection feature
    </description>
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>hibernate.cfg.xml</value>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>
    <bean id="docServerConfig" class="just.docserver.config.DocServerConfig" singleton="true">
        <property name="config"><value>docsrv.conf</value></property>
        <!-- contextPath is which url path the document server resides, KEEP it sync with actual deployment -->
        <property name="contextPath"><value>/axis</value></property>
    </bean>    
    <!--DAO classes definition begin-->
    <bean id="docDao" class="just.docserver.dal.daoimpl.doc.DocDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userFileDao" class="just.docserver.dal.daoimpl.doc.UserFileDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="docSettingDao" class="just.docserver.dal.daoimpl.doc.DocSettingDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>    
    <bean id="userDocumentDao" class="just.docserver.dal.daoimpl.doc.UserDocumentDaoImpl">
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
        <property name="docDao"><ref local="docDao"/></property>
        <property name="docSettingDao"><ref local="docSettingDao"/></property>
        <property name="userFileDao"><ref local="userFileDao"/></property>
    </bean>    
    <!--DAO classes definition end-->
    
    <!--  Service definition begin -->
    <bean id="userDocumentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager">
        <ref local="transactionManager"/>
      </property>  
      <property name="target">
          <bean class="just.docserver.UserDocumentManagerImpl">
              <property name="docDao"><ref local="docDao"/></property>
              <property name="docSettingDao"><ref local="docSettingDao"/></property>
              <property name="userDocumentDao"><ref local="userDocumentDao"/></property>
              <property name="userFileDao"><ref local="userFileDao"/></property>
              <property name="docServerConfig"><ref local="docServerConfig"/></property>
          </bean>
      </property>
      <property name="proxyInterfaces"><value>just.docserver.UserDocumentManager</value></property>
      <property name="transactionAttributes">
        <props>
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
      </property>
    </bean>    
    <!--  Service definition end -->
</beans>
这样整个配置更为简洁清晰,而且更适合于代码生成工具来生成这些配置,进一步提高开发效率。
总结:
本文归纳了Spring声明性事务配置几种方式,BeanNameAutoProxyCreator,TransactionProxyFactoryBean即TransactionProxyFactoryBean加嵌套式Target bean。方法一适用于有大量bean需要声明性事务配置的情形。方法二、三配置更加灵活。方法三比方法二更加简洁、紧凑,十分适用于代码生成。另外,方法有个缺点,如果bean实现某些接口,使用方法一无法指定对这些接口进行截获(利用ProxyFactoryBean的proxyInterfaces属性),从而无法使用JDK的动态代理,只能使用CGLIB来实现方法截获。

转载于:https://my.oschina.net/wangjian95/blog/37774

你可能感兴趣的文章
MySQL数据库的优化(上)单机MySQL数据库的优化
查看>>
hdu4366 Successor
查看>>
Scala使用Akka模拟RPC机制代码2
查看>>
this与JavaScrip中的四种调用模式
查看>>
java 实现打印当前月份的日历
查看>>
Base64转码和解码的帮助类
查看>>
侃侃正向代理和反向代理
查看>>
PLSQL连接oracel数据库_用户无法登陆_oci.dll_配置问题
查看>>
李洪强iOS经典面试题37-解释垃圾回收的原理
查看>>
多校第二场 1004 hdu 5303 Delicious Apples(背包+贪心)
查看>>
Executor , ExecutorService 和 Executors
查看>>
关于图数据库查询语言:Cypher
查看>>
Android中m、mm、mmm、mma、mmma的区别
查看>>
知道各个层使用的是哪个数据交换设备
查看>>
MySQL索引类型总结和使用技巧以及注意事项
查看>>
iOS:在cell中使用倒计时的最佳方法
查看>>
深入浅出空间索引:为什么需要空间索引
查看>>
EF 数据版本号,处理具体使用方法 RowVersion / Timestamp 使用方法。进行自动处理并发修改...
查看>>
centos6.5关闭ipv6
查看>>
springboot整合mybatis将sql打印到日志
查看>>