欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring声明式事务解析

程序员文章站 2024-03-11 22:58:49
一、spring声明式事务 1.1 spring的事务管理器 spring没有直接管理事务,而是将管理事务的责任委托给jta或相应的持久性机制所提供的某个特定平...

一、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声明式事务解析

spring与hibernate

spring声明式事务解析

说明:

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

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

1.2 以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" 此配置可以解决事务嵌套问题,何为事务嵌套?

比如:

spring声明式事务解析

在工作流框架和操作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中,所以会导致大量的缓存中的数据被长时间停留在内存中。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。