Spring事务管理

Posted 蜗牛不怕慢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring事务管理相关的知识,希望对你有一定的参考价值。

Spring的事务管理分为声明式事务管理跟编程式事务管理。声明式就是在Spring的配置文件中进行相关配置,编程式就是用注解的方式写到代码里。

一、声明式事务管理

        Spring声明式事务管理在配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。DataSource、 TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
声明式事务配置主要有3种,下面我们就一起看看三种声明式事务的具体配置

基础配置

<bean name="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="mappingLocations">
			<list>
				<value>classpath*:META-INF/mapping/*.xml</value>
			</list>
		</property>
		<property name="packagesToScan">
			<list>
				<value>com.sf.sgs.**.domain</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">$hibernate.dialect:org.hibernate.dialect.mysqlDialect
				</prop>
				<prop key="hibernate.show_sql">$hibernate.show_sql:true</prop>
				<prop key="hibernate.format_sql">$hibernate.format_sql:false</prop>
				<prop key="hibernate.jdbc.batch_size">$hibernate.batch_size:50</prop>
				<prop key="hibernate.connection.useUnicode">$hibernate.useUnicode:true</prop>
				<prop key="hibernate.connection.characterEncoding">$hibernate.characterEncoding:UTF8</prop>
			</props>
		</property>
	</bean>

     <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
		destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="$mysql.jdbc.url" />
		<property name="username" value="$mysql.jdbc.username" />
		<property name="password" value="$mysql.jdbc.password" />

		<property name="maxActive" value="$maxActive" />
		<property name="initialSize" value="$initialSize" />
		<property name="maxWait" value="$maxWait" />
		<property name="minIdle" value="$minIdle" />

		<property name="validationQuery" value="$validationQuery" />
		<property name="testWhileIdle" value="$testWhileIdle" />
		<property name="testOnBorrow" value="$testOnBorrow" />
		<property name="testOnReturn" value="$testOnReturn" />
		<!-- 配置连接闲置时间,单位是毫秒 申请连接时检查连接是否闲置超时时用到该参数 -->
		<property name="timeBetweenEvictionRunsMillis" value="$timeBetweenEvictionRunsMillis" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="$minEvictableIdleTimeMillis" />
		<property name="connectionInitSqls" value="$collectionInit"/>

		<!-- 打开removeAbandoned功能 对于长时间不使用的连接强制关闭 -->
		<!--property name="removeAbandoned" value="$removeAbandoned" / -->
		<!-- 1800秒,也就是连接超过30分钟未关闭则开始关闭连接 -->
		<!--property name="removeAbandonedTimeout" value="$removeAbandonedTimeout" 
			/ -->
		<!-- 关闭abanded连接时输出错误日志 -->
		<!--property name="logAbandoned" value="$logAbandoned" / -->
	</bean>

        <bean name="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
1.tx标签

<aop:config>
		<aop:advisor pointcut="execution(* com.service..*.*(..))" advice-ref="txAdviceShield"/>
	</aop:config>
	
	 <tx:advice id="txAdviceShield" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="insert*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="update*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="delete*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="create*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="add*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="register*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="assign*" propagation="REQUIRED" rollback-for="Throwable"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
execution:其中第一个*代表返回值,第二*代表dao下子包,第三个*代表方法名,“(..)”代表方法参数。

2.代理方式

<!-- 第二种配置事务的方式 ,代理-->
<bean id="transactionProxy"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"    abstract="true">
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
        </props>
    </property>
</bean>
<bean id="userDao" parent="transactionProxy">
    <property name="target">
        <!-- 用bean代替ref的方式-->
        <bean class="com.dao.UserDaoImpl">
            <property name="sessionFactory" ref="sessionFactory"></property>
        </bean>
    </property>
</bean>
将transactionProxy的abstract属性设置为"true",然后将具体的Dao的parent属性设置为"transactionProxy",可以精简代码。
在很多场合,使用ProxyFactoryBean来显式的创建AOP代理这种方式会使编写配置文件的工作量大大增加,由于要从 ProxyFactoryBean获得代理对象,也会使应用和Spring之间的耦合度增加。
3.拦截器方式

BeanNameAutoProxyCreator类允许我们通过Bean的name属性来指定代理的Bean。它暴露了 java.lang.String[]类型的beanNames和 interceptorNames属性。beanNames可以指定被代理的Bean名字列表,支持“*”通配符,例如“*DAO”表示所有名字以 “DAO”结尾的Bean。interceptorNames指定通知(Advice)列表(methodinterceper是Advice中的round类型),或者通知者(Advisor)列表。

<!-- 第三种配置事务的方式,拦截器 (不常用)-->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"></property>
    <property name="transactionAttributes">
        <props>
            <prop key="add*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="modify*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="del*">PROPAGATION_REQUIRED, -Exception</prop>
            <prop key="*">PROPAGATION_REQUIRED, readOnly</prop>
        </props>
    </property>
</bean>
<bean id="proxyFactory" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="interceptorNames">
        <list>
            <value>transactionInterceptor</value>
        </list>
    </property>
    <property name="beanNames">
        <list>
            <value>*Dao</value>
        </list>
    </property>
</bean>
Spring事务类型详解:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
二、编程式事务

编程式即采用注解的方式,需要注意的是,使用注解的方式需要在Spring的配置文件中加入一句话:<context:annotation-config />,其作用是开启注解的方式。具体配置如下:

<!--开启注解方式-->
<context:annotation-config />

<!-- 配置sessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:config/hibernate.cfg.xml</value>
    </property>
    <property name="packagesToScan">
        <list>
            <value>com.entity</value>
        </list>
    </property>
</bean>

<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- 第四种配置事务的方式,注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

package com.dao;

import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.entity.User;

@Transactional
public class UserDaoImpl_BAK extends HibernateTemplate 

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void addUser(User user) throws Exception 
        this.save(user);
    

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void modifyUser(User user) 
        this.update(user);
    

    @Transactional(propagation=Propagation.REQUIRED,rollbackForClassName="Exception")
    public void delUser(String username) 
        this.delete(this.load(User.class, username));
    

    @Transactional(readOnly=true)
    public void selectUser() 

    


类头的@Transactional为默认事务配置,如方法没有自己的事务类型,则按默认事务,如有自己的配置,则按自己的配置。

以上四种配置方式最常用的还是第一、二种,第三种是比较老旧的方式,而注解的方式不太适合比较大的项目,用于简单的小项目还是很好的,其特点就是简单明了。每种方法都有每种方法的特点跟适用的环境,没有绝对的好与坏,只不过前两种在实际的工作当中用的更多一些。
 参考:
       [1]http://www.cnblogs.com/newsouls/p/3988216.html





以上是关于Spring事务管理的主要内容,如果未能解决你的问题,请参考以下文章

带有条件通知者的消息队列

观察者模式与事件委托

知人者智,自知者明

观察者模式

Spring之FactoryBean

观察者模式和java委托