• 【spring基础】spring声明式事务详解


    一、spring声明式事务

    1.1 spring的事务管理器

    spring没有直接管理事务,而是将管理事务的责任委托给JTA或相应的持久性机制所提供的某个特定平台的事务实现。spring容器负责事物的操作,spring容器充当切面,事务的方法称为增强处理,生成的代理对象的方法就是目标方法+增强也就是crud+事务程序员只用做crud的操作,也就是目标方法和声明哪些方法应该在事务中运行

    Spring提供了许多内置事务管理器实现:

    • DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理;
    • JdoTransactionManager:位于org.springframework.orm.jdo包中,提供对单个javax.jdo.PersistenceManagerFactory事务管理,用于集成JDO框架时的事务管理;
    • JpaTransactionManager:位于org.springframework.orm.jpa包中,提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理;
    • HibernateTransactionManager:位于org.springframework.orm.hibernate3包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate 3.2+版本;
    • JtaTransactionManager:位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器;
    • OC4JjtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对OC4J10.1.3+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
    • WebSphereUowTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebSphere 6.0+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
    • WebLogicJtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebLogic 8.1+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持。

    Spring不仅提供这些事务管理器,还提供对如JMS事务管理的管理器等,Spring提供一致的事务抽象如图所示

    spring与hibernate

    说明:

    spring在调用具体的事务管理器之前做了一些准备工作,提前设置事务的读写策略,而这些事务策略是公共的东西,是写在spring的配置文件中的,这些内容的处理需要放在抽象类中去做


    二、spring与hibernate整合中的事务处理

    1.1 以xml形式

    引入properties配置文件

     <property name="locations">  
          <value>classpath:jdbc.properties</value>  
     </property> 

    配置dbcp数据源

    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">  
            <property name="driverClassName" value="${jdbc.driverClassName}" />  
            <property name="url" value="${jdbc.url}" />  
            <property name="username" value="${jdbc.username}" />  
            <property name="password" value="${jdbc.password}" />  
     </bean>  

    引入sessionfactory,使用hibernate外部配置文件

    <bean id="sessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
            <property name="configLocation">  
                <value>classpath:hibernate.cfg.xml</value>  
            </property>  
    </bean>  

    注入dao和service层

      <bean id="personDao" class="cn.qjc.hibernate.dao.impl.PersonDaoImpl">  
            <property name="sessionFactory">  
                <ref bean="sessionFactory2"/>  
            </property>  
        </bean>  
          
        <bean id="personService" class="cn.qjc.hibernate.service.impl.PersonServiceImpl">  
            <property name="personDao">  
                <ref bean="personDao"/>  
            </property>  
        </bean>  

    配置hibernate事务管理器

      <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
            <property name="sessionFactory">  
                <ref bean="sessionFactory2"/>  
            </property>  
         </bean>  

    配置声明式事务

    作用:

      1、告诉spring容器事务管理器

      2、告诉spring容器什么样的方法使用什么样的事务

      <tx:advice transaction-manager="transactionManager" id="tx">  
            <tx:attributes>  
                <!--   
                    name 目标方法的范围  
                    islation 隔离级别  
                    propagation 传播属性              
                    read-only  
                        true  只读事务  
                        false 读写事务  
                 -->  
                <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>  
            </tx:attributes>  
         </tx:advice>  

    配置切入点

      <aop:config>  
            <aop:pointcut expression="execution(* cn.qjc.hibernate.service.impl.*.*(..))" id="perform"/>  
               <span style="white-space:pre"> </span><!-- 将切入点应用到增强方法 -->  
            <aop:advisor advice-ref="tx" pointcut-ref="perform"/>  
         </aop:config>  

    dao实现类

     * 实现方法一:继承HibernateDaoSupport  
     * @author qjc  
     */  
    public class PersonDaoImpl extends HibernateDaoSupport implements PersonDao{  
      
        @Override  
        public void savePerson(Person person) {  
            this.getHibernateTemplate().save(person);  
        }  
    }  

    测试

    ...

    注意:

    1、如果一个DAO类继承了HibernateDaoSupport,只需要在spring配置文件中注入SessionFactory就可以了。

    2、如果一个DAO类没有继承HibernateDaoSupport,需要有一个SessionFactory的属性,并且在配置文件中进行注入。

      <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">  
            <property name="sessionFactory" ref="sessionFactory2"></property>  
        </bean>  

    1.2 以注解形式

    1、在配置文件中应用spring的自动扫描机制

    <context:component-scan base-package="cn.qjc"/> 

    2、在配置文件中引入注解解析器

    <tx:annotation-driven transaction-manager="transactionManager"/> 

    3、在service层通过@Transaction进行注解

    注意:如果在类级别上被注解为只读事务,但是这个类中的方法中@Transaction注解的事务设置将优先于类级别注解的事务设置。

    1.3 spring事务的传播属性

      required: 业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新事务(默认) 

      not-supported:spring容器不开启事务,如果方法在一个事务中被调用,该事务会被挂起,该方法结束后,事务恢复

      requiresnew:不管是否存在事务,业务方法总会创建一个新事务。

      mandatorky: 业务方法只能在一个已经存在的事务中执行,如果业务方法在没有事务下调用,容器抛出例外。

    此外还有supports、never、nested等属性,但是通常使用默认

    propagation="required" 此配置可以解决事务嵌套问题,何为事务嵌套?

    比如:

    在工作流框架和操作service层的某个方法中都存在事务,service层也有自己的事务,当service执行的时候,就会出现事务嵌套,即方法本身有事务,方法中的方法还有事务,这就是事务嵌套。而spring通过事务传播属性propagation="required"解决了这一问题。

    1.4 OpenInSessionView

    在s2sh整合以后,spring管理事务,由于使用的是spring的声明式事务处理方式,所以在调用this.getHibernateTemplate()这个方法执行完之后,session立即关闭,如果当前执行的方法有事务,当事务环境的方法被调用完毕后session关闭。所以当值在页面输出时会产生异常。

    处理方式为:OpenSessionInview模式(web.xml中配置)

    <filter>  
        <filter-name>hibernateFilter</filter-name>  
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>  
          
        <!-- singleSession默认为true,若设置为false则等于没有OpenSessionInView  -->  
        <init-param>  
            <param-name>singleSession</param-name>  
            <param-value>true</param-value>  
        </init-param>  
     </filter>  
    <filter-mapping> <filter-name>hibernateFilter</filter-name>   <url-pattern>/PersonService</url-pattern> </filter-mapping>

    从上面代码可以看出,当提交一个请求时,OpenSessionInView中已经把session开启了,在response以后才要关闭session,也就意味着有了openSessionInView必须在struts2的过滤器之前。(放struts2过滤器位置上面)

    但是开启OpenSessionInView也有缺点:因为session关闭被延后了,而hibernate的一级缓存在session中,所以会导致大量的缓存中的数据被长时间停留在内存中。

  • 相关阅读:
    JSP版LCX:端口转发神器 KPortTran
    使用 JavaScript 实现对 PDF 的全文索引
    伙伴分配器的一个极简实现
    java创建线程的三种方式及其对照
    【版本号公布】Jeecg-P3 1.0 公布,J2EE微服务框架(插件开发)
    linux c 获取当前执行进程总数
    C++入门学习——模板
    GSON学习笔记之初识GSON
    Python学习笔记_Python对象
    怎样在OTN站点高速找到asm包并下载 (Oracle RAC)
  • 原文地址:https://www.cnblogs.com/dooor/p/5342400.html
Copyright © 2020-2023  润新知