spring没有直接管理事务,而是将管理事务的责任委托给JTA或相应的持久性机制所提供的某个特定平台的事务实现。spring容器负责事物的操做,spring容器充当切面,事务的方法称为加强处理,生成的代理对象的方法就是目标方法+加强也就是crud+事务程序员只用作crud的操做,也就是目标方法和声明哪些方法应该在事务中运行。java
Spring提供了许多内置事务管理器实现:程序员
Spring不只提供这些事务管理器,还提供对如JMS事务管理的管理器等,Spring提供一致的事务抽象如图所示web
spring与hibernatespring
说明:sql
spring在调用具体的事务管理器以前作了一些准备工做,提早设置事务的读写策略,而这些事务策略是公共的东西,是写在spring的配置文件中的,这些内容的处理须要放在抽象类中去作express
引入properties配置文件apache
<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层session
<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>
配置声明式事务
做用:
一、告诉spring容器事务管理器
二、告诉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); } }
测试
...
注意:
一、若是一个DAO类继承了HibernateDaoSupport,只须要在spring配置文件中注入SessionFactory就能够了。
二、若是一个DAO类没有继承HibernateDaoSupport,须要有一个SessionFactory的属性,而且在配置文件中进行注入。
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory2"></property>
</bean>
一、在配置文件中应用spring的自动扫描机制
<context:component-scan base-package="cn.qjc"/>
二、在配置文件中引入注解解析器
<tx:annotation-driven transaction-manager="transactionManager"/>
三、在service层经过@Transaction进行注解
注意:若是在类级别上被注解为只读事务,可是这个类中的方法中@Transaction注解的事务设置将优先于类级别注解的事务设置。
required: 业务方法须要在一个事务中运行。若是方法运行时,已经处在一个事务中,那么加入到该事务,不然为本身建立一个新事务(默认)
not-supported:spring容器不开启事务,若是方法在一个事务中被调用,该事务会被挂起,该方法结束后,事务恢复
requiresnew:无论是否存在事务,业务方法总会建立一个新事务。
mandatorky: 业务方法只能在一个已经存在的事务中执行,若是业务方法在没有事务下调用,容器抛出例外。
此外还有supports、never、nested等属性,可是一般使用默认
propagation="required" 此配置能够解决事务嵌套问题,何为事务嵌套?
好比:
在工做流框架和操做service层的某个方法中都存在事务,service层也有本身的事务,当service执行的时候,就会出现事务嵌套,即方法自己有事务,方法中的方法还有事务,这就是事务嵌套。而spring经过事务传播属性propagation="required"解决了这一问题。
在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中,因此会致使大量的缓存中的数据被长时间停留在内存中。