zoukankan      html  css  js  c++  java
  • Spring学习笔记(四)-- Spring事务全面分析

    通过本系列的文章对Spring的介绍,我们对Spring的使用和两个核心功能IOC、AOP已经有了初步的了解,结合我个人工作的情况,因为项目是金融

    统。那对事务的控制是不可缺少的。而且是很严格的控制。

    依据我对项目的研究,它在管理模块用的是JTA事务,而在交易模块用的是JDBC的事

    务,可是。全部的这些事务的使用,都是用Spring封装后的编程式事务。我在看完《Spring In Action》后。在网上看了下大家对Spring事务的理解。貌

    似都没有真正的文章是去全面剖析Spring对这些事务的支持,特此写下这篇博文,以分食众人。

    提示本博文将讲授Spring事务的管理功能,包含编程式事务和声明式事务。

    经过对本博文的了解。你将能够理解Spring事务管理的实质,并合理运用

    之。可是本博文假定您已经掌控了java的基本知识,并对Spring有一定的了解,假设您对Spring还不是非常了解。请參考本系列的文章。同一时候您还须要具

    有一定的事务管理的常识,如事务的边界、隔离的级别等等。

    本文将直接行使这些概念而不做详细说明。


    Spring 事务管理最重要的API有三个: TransactionDefinition 、 PlatformTransactionManager 、 TransactionStatus。所谓事务管理,事实上就是“按

    给定的事务规则来运行提交或者回滚操作”。“给定的事务规则”就是用 TransactionDefinition 表示的,“依照……来运行提交或者回滚操作”便是用 

    PlatformTransactionManager 来表示。TransactionStatus 用于表示一个执行着的事务的状态 。


    Spring事务属性剖析

    事务控制对企业系统而言至关主要。它担保了用户的每次操作都是可靠的,即便出现了异常情况,也不至于损坏后台数据的完性。就像银行的自助取

    款机,常日都能正常为客户干事。然而也难免碰到操作过程中宕机的情形。此时,事务就必需确保出问题账户的操作不生效,就像用户刚才全然没

    有使用过取款机一样,以担保用户和银行的利益都不受损失。在Spring中,事务是通过 TransactionDefinition 接口来定义的。该接口包括与事务属性有

    关的方法,详细如清单1所看到的:

    清单 1.TransactionDefinition 接口中定义的主要方法:

    public interface TransactionDefinition{
    int getIsolationLevel();//isolation 隔离级别
    int getPropagationBehavior();//Propagation 传播行为
    int getTimeout();//超时时间
    boolean isReadOnly();//是否仅仅读
    }

    在剖析第一个属性之前。我们有必要先了解一下几个概念脏读、不可反复读和幻读:

    1. 脏读 ( 事务没提交,提前读取 ) :脏读就是指当一个事务正在訪问数据,而且对数据进行了改动,而这样的改动还没有提交到数据库中,这时,另外一

    个事务也訪问这个数据,然后使用了这个数据

    2. 不可反复读 ( 两次读的不一致 ) :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也訪问该同一数据。

    那么,在第一

    个事务中的两次读数据之间。因为第二个事务的改动,那么第一个事务两次读到的的数据可能是不一样的。

    这样就发生了在一个事务内两次读到

    的数据不一样的,因此称为是不可反复读。

    3. 幻读 : 是指当事务不是独立运行时发生的一种现象。比如第一个事务对一个表中的数据进行了改动,这样的改动涉及到表中的所有数据行。同一时候。第二

    个事务也改动这个表中的数据,这样的改动是向表中插入新的一行数据。

    那么。以后就会发生操作第一个事务的用户发现表中还有没有改动的数据

    行。就好象发生了幻觉一样。


    接下来我们能够进入我们的第一个属性的剖析了:事务隔离级别。隔离级别是指若干个并发的事务之间的隔离程度。


    TransactionDefinition 接口中定义了五个表示隔离级别的常量:

    TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言。通常这值

    TransactionDefinition.ISOLATION_READ_COMMITTED 。

    TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务能够读取还有一个事务改动但还没有提交的数据。该级别不能防止脏读和不可反复读,因此非常少使用该隔离级别。

    TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务仅仅能读取还有一个事务已经提交的数据。

    该级别可以防止脏读。这也是大多数情况下的推荐值。

    TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中能够多次反复运行某个查询,并且每次返回的记录

    都同样。

    即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。

    该级别能够防止脏读和不可反复读。

    TransactionDefinition.ISOLATION_SERIALIZABLE:全部的事务依次逐个运行。这样事务之间就全然不可能产生干扰,也就是说,该级别能够防止脏

    读、不可反复读和幻读。

    可是这将严重影响程序的性能。通常情况下也不会用到该级别。

    事务传播行为

    所谓事务的传播行为是指。假设在開始当前事务之前,一个事务上下文已经存在,此时有若干选项能够指定一个事务性方法的运行行为。


    TransactionDefinition 定义中包含了例如以下几个表示传播行为的常量:

    TransactionDefinition.PROPAGATION_REQUIRED :假设当前存在事务,则增加该事务;假设当前没有事务,则创建一个新的事

    TransactionDefinition.PROPAGATION_REQUIRES_NEW :创建一个新的事务。假设当前存在事务,则把当前事务挂起。

    TransactionDefinition.PROPAGATION_SUPPORTS :假设当前存在事务,则增加该事务;假设当前没有事务,则以非事务的方式继续执行。

    TransactionDefinition.PROPAGATION_NOT_SUPPORTED :以非事务方式执行,假设当前存在事务,则把当前事务挂起。

    TransactionDefinition.PROPAGATION_NEVER :以非事务方式执行。假设当前存在事务,则抛出异常。

    TransactionDefinition.PROPAGATION_MANDATORY :假设当前存在事务,则增加该事务。假设当前没有事务。则抛出异常。


    TransactionDefinition.PROPAGATION_NESTED :假设当前存在事务,则创建一个事务作为当前事务的嵌套事务来执行;假设当前没有事务,则该取

    值等价于 TransactionDefinition.PROPAGATION_REQUIRED。


    这里须要指出的是。前面的六种事务传播行为是 Spring 从 EJB 中引入的,他们共享同样的概念。而PROPAGATION_NESTED 是 Spring 所特有的。

    以 PROPAGATION_NESTED 启动的事务内嵌于外部事务中(假设存在外部事务的话)。此时。内嵌事务并非一个独立的事务,它依赖于外部事务

    的存在,仅仅有外部事务的提交,才干引起内部事务的提交,嵌套的子事务不能单独提交。

    假设熟悉 JDBC 中的保存点的概念。那嵌套事务就非常easy理解

    了,事实上嵌套的子事务就是保存点的一个应用,一个事务中能够包含多个保存点。每个嵌套子事务。

    另外,外部事务的回滚也会导致嵌套子事务的回

    事务挂起

    如:方法 A 支持事务。方法 B 不支持事务。方法 A 调用方法 B 。在方法 A 開始执行时。系统为它建立 Transaction 方法A中对于数据库的处理操

    作。会在该Transaction 的控制之下。

    这时,方法 A 调用方法 B, 方法 A 打开的 Transaction 将挂起,方法B中任何数据库的操作,都不在该

    Transaction 的管理之下。当方法 B 返回。方法 A 继续执行,之前的Transaction恢复,后面的数据库操作继续在该 Transaction 的控制之下提交或回

    滚。

    事务超时

    所谓事务超时。就是指一个事务所同意运行的最长时间。假设超过该时间限制但事务还没有完毕,则自己主动回滚事务。在 TransactionDefinition 中以 int 

    的值来表示超时时间,其单位是秒。

    事务的仅仅读属性

    事务的仅仅读属性是指,对事务性资源进行仅仅读操作或者是读写操作。

    假设确定仅仅对事务性资源进行仅仅读操作。那么我们能够将事务标志为仅仅读的。以提

    高事务处理的性能。

    在 TransactionDefinition中以boolean 类型来表示该事务是否仅仅读。

    事务的回滚规则

    通常情况下,假设在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务;假设没有抛出不论什么异常,或者抛出了已检查

    异常。则仍然提交事务。

    这通常也是大多数开发人员希望的处理方式,也是 EJB 中的默认处理方式。可是,我们能够依据须要人为控制事务在抛出某些

    未检查异常时仍然提交事务,或者在抛出某些已检查异常时回滚事务。


    PlatformTransactionManager 

    清单2.PlatformTransactionManager 接口中定义的主要方法:

    Public interface PlatformTransactionManager{
      TransactionStatus getTransaction(TransactionDefinition definition)
       throws TransactionException;
       void commit(TransactionStatus status)throws TransactionException;
       void rollback(TransactionStatus status)throws TransactionException;
    }

    依据底层所使用的不同的持久化 API 或框架, PlatformTransactionManager 的主要实现类大致例如以下:

    1. DataSourceTransactionManager :适用于使用 JDBC 和 iBatis 进行数据持久化操作的情况。

    2. HibernateTransactionManager :适用于使用 Hibernate 进行数据持久化操作的情况。

    3.JpaTransactionManager :适用于使用 JPA 进行数据持久化操作的情况。

    4.另外还有 JtaTransactionManager 、 JdoTransactionManager 、 JmsTransactionManager等等。


    假设我们使用 JTA 进行事务管理,我们能够通过 JNDI 和 Spring 的 JtaTransactionManager 来获取一个容器管理的

    DataSourceJtaTransactionManager 不须要知道 DataSource 和其它特定的资源,由于它将使用容器提供的全局事务管理。而对于其它事务管理

    器,比方DataSourceTransactionManager,在定义时须要提供底层的数据源作为其属性,也就是 DataSource 。与HibernateTransactionManager 对

    应的是 SessionFactory ,与 JpaTransactionManager 相应的是EntityManagerFactory 等等。


    TransactionStatus

    PlatformTransactionManager.getTransaction( … ) 方法返回一个 TransactionStatus 对象。

    返回的TransactionStatus 对象可能代表一个新的或已经存

    在的事务(假设在当前调用堆栈有一个符合条件的事务)。 TransactionStatus 接口提供了一个简单的控制事务运行和查询事务状态的方法。该接口定

    义如清单3所看到的:

    清单 3. TransactionStatus 接口中定义的主要方法

    public  interface TransactionStatus{
       boolean isNewTransaction();
       void setRollbackOnly();
       boolean isRollbackOnly();
    }

    编程式事务管理

    Spring的编程式事务管理概述

    在Spring 出现曾经,编程式事务管理对基于 POJO 的应用来说是唯一选择。

    用过 Hibernate 的人应该都知道,我们须要在代码中显式调用 beginTrans

    action() 、 commit() 、 rollback() 等事务管理相关的方法,这就是编程式事务管理。通过 Spring 提供的事务管理 API ,我们能够在代码中灵活控制事

    务的运行。在底层, Spring 仍然将事务操作托付给底层的持久化框架来运行。

    基于底层API的编程式事务管理

    依据 PlatformTransactionManager 、 TransactionDefinition 和 TransactionStatus 三个核心接口,我们全然能够通过编程的方式来进行事务管理。示

    例代码如清单 4 所看到的(详细代码见我的java事务系列博文):

    public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    private TransactionDefinition txDefinition;
    private PlatformTransactionManager txManager;
    ......
    public boolean transfer(Long fromId 。 Long toId 。 double amount) {
    TransactionStatus txStatus = txManager.getTransaction(txDefinition);
    boolean result = false;
    try {
    result = bankDao.transfer(fromId , toId , amount);
    txManager.commit(txStatus);
    } catch (Exception e) {
    result = false;
    txManager.rollback(txStatus);
    System.out.println("Transfer Error!");
    }
    return result;
    }
    }

    对应的配置文件例如以下:

    <bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl">
    <property name="bankDao" ref="bankDao"/>
    <property name="txManager" ref="transactionManager "/>
    <property name="txDefinition">
    <bean class="org.springframework.transaction.support.DefaultTransactionDefinition ">
    <property name="propagationBehaviorName " value="PROPAGATION_REQUIRED "/>
    </bean>
    </property>
    </bean>

    如上所看到的,我们在类中添加了两个属性:一个是 TransactionDefinition 类型的属性,它用于定义一个事务,;还有一个是 PlatformTransactionManager 类型的属性。用

    于运行事务管理操作。

    假设方法须要实施事务管理,我们首先须要在方法開始运行前启动一个事务,调用PlatformTransactionManager.getTransactio

    n(...) 方法便可启动一个事务。创建并启动了事务之后,便能够開始编写业务逻辑代码,然后在适当的地方运行事务的提交或者回滚。

    基于TransactionTemplate的编程式事务

    通过前面的演示样例能够发现。这样的事务管理方式非常easy理解。但令人头疼的是,事务管理的代码散落在业务逻辑代码中。破坏了原有代码的条理性,而且

    每个业务方法都包括了类似的启动事务、提交 / 回滚事务的样板代码幸运的是,Spring也意识到了这些问题,并提供了简化的方法,这就是Spring在

    数据DAO层常常使用的模板回调方法。如清单6所看到的:

    清单6. 基于 TransactionTemplate 的事务管理演示样例代码

    public class BankServiceImpl implements BankService 
    {
    	private BankDao bankDao;
    	private TransactionTemplate transactionTemplate;
    	......
    	public boolean transfer(final Long fromId, final Long toId, final double amount) 
    	{
    		return (Boolean) transactionTemplate.execute(new TransactionCallback()
    		{
    			public Object doInTransaction(TransactionStatus status) 
    			{
    				Object result;
    				try {
    					result = bankDao.transfer(fromId, toId, amount);
    				} catch (Exception e) {
    					status.setRollbackOnly();
    					result = false;
    					System.out.println("Transfer Error!");
    				}
    				return result;
    			}
    		});
    	}
    }

    相应的bean配置实比例如以下:

    清单 7. 基于 TransactionTemplate 的事务管理演示样例bean文件

    <bean id="bankService"
    class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
    <property name="bankDao" ref="bankDao"/>
    <property name="transactionTemplate" ref="transactionTemplate"/>
    </bean>

    因为眼下我所开发的系统是金融系统,金融系统本身对事务的要求很之高,不但要求可以精确控制事务的边界,它的開始、束甚

    至在异常发生后的处理。都必须处于我们的控制之下(就一控制狂)。所以我们项目选择的是Spring编程式事务的这样的实现式。

    声明式事务管理

    Spring 的声明式事务管理概述

    Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。

    其本质是对方法前后进行拦截,然后在目标方法開始之前创建或者增加一个事务,在执

    行完目标方法之后依据运行情况提交或者回滚事务。声明式事务最大的长处就是不须要通过编程的方式管理事务。这样就不须要在业务逻辑代码中掺杂

    事务管理代码,仅仅需在配置文件里做相关的事务规则声明(或通过等价的基于标注的方式),便能够将事务规则应用到业务逻辑中。由于事务管理本身

    就是一个典型的横切逻辑,正是 AOP 的用武之地。Spring 开发团队也意识到了这一点,为声明式事务提供了简单而强大的支持。和编程式事务相比,

    声明式事务唯一不足地方是,后者的最细粒度仅仅能作用到方法级别。无法做到像编程式事务的代码块级别。可是即便有这种需求。也存在非常多变通的

    方法,比方,能够将须要进行事务管理的代码块独立为方法等等。

    以下就来看看 Spring 为我们提供的声明式事务管理功能。



    基于TransactionProxyFactoryBean的声明式事务管理

    清单 9. 基于 TransactionProxyFactoryBean 的事务管理演示样例配置文件

    <beans......>
    ......
    	<bean id="bankServiceTarget"
    		class="footmark.spring.core.tx.declare.classic.BankServiceImpl">
    		<property name="bankDao" ref="bankDao"/>
    	</bean>
     
    	<bean id="bankService"
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean ">
    		<property name="target" ref="bankServiceTarget "/>
    		<property name="transactionManager" ref="transactionManager "/>
    		<property name="transactionAttributes">
    			<props>
    				<prop key="transfer">PROPAGATION_REQUIRED </prop>
    			</props>
    		</property>
    	</bean>
    ......
    </beans>

    显式为每个业务类配置一个 TransactionProxyFactoryBean 的做法将使得代码显得过于刻板


    基于<tx> 命名空间的声明式事务管理

    前面那种声明式事务配置方式奠定了 Spring 声明式事务管理的基石。在此基础上,Spring 2.x 引入了<tx>命名空间,结合使用<aop> 命名空间,带给

    开发者配置声明式事务的全新体验,配置变得更加简单和灵活。另外,得益于 <aop> 命名空间的切点表达式支持。声明式事务也变得更加强大

    <beans......>
    ......
    	<bean id="bankService"
    		class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
    		<property name="bankDao" ref="bankDao"/>
    	</bean>
    	<tx:advice id="bankAdvice" transaction-manager="transactionManager">
    		<tx:attributes>
    			<tx:method name="transfer" propagation="REQUIRED"/>
    		</tx:attributes>
    	</tx:advice>
    	<aop:config>
    		<aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))" />
    		<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut" />
    	</aop:config>
    ......
    </beans>

    因为使用了切点表达式,我们就不须要针对每个业务类创建一个代理对象了。另外,假设配置的事务管理器 Bean 的名字取值

    “transactionManager ”。则我们能够省略<tx:advice>的 transaction-manager 属性,由于该属性的默认值即为“ transactionManager ”

    基于 @Transactional 的声明式事务管理

    除了基于命名空间的事务配置方式。 Spring 2.x 还引入了基于 Annotation 的方式,详细主要涉及 @Transactional 标注。@Transactional 能够作用于

    接口、接口方法、类以及类方法上。当作用于类上时,该类的全部 public 方法将都具有该类型的事务属性,同一时候,我们也能够在方法级别使用该标注来

    覆盖类级别的定义。如清单 12 所看到的:

    清单 12. 基于 @Transactional 的事务管理演示样例配置文件

    @Transactional(propagation = Propagation.REQUIRED)
    public boolean transfer(Long fromId , Long toId , double amount) 
    {
    	return bankDao.transfer(fromId , toId , amount);
    }

    Spring 使用 BeanPostProcessor 来处理 Bean 中的标注。因此我们须要在配置文件里作例如以下声明来激活该后处理 Bean ,如清单 13 所看到的

    清单 13. 启用后处理 Bean 的配置

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

    与前面相似。 transaction-manager 属性的默认值是 transactionManager ,假设事务管理器 Bean 的名字即为该值,则能够省略该属性。尽管 @Transactional 注解能够

    作用于接口、接口方法、类以及类方法上。可是 Spring 小组建议不要在接口或者接口方法上使用该注解,由于这仅仅有在使用基于接口的代理时它才会

    生效。另外, @Transactional 注解应该仅仅被应用到 public 方法上。这是由 Spring AOP 的本质决定的。

    假设你在 protected 、 private 或者默认可见

    性的方法上使用 @Transactional 注解。这将被忽略,也不会抛出不论什么异常。

    基于 <tx> 命名空间和基于 @Transactional 的事务声明方式各有优缺点。

    基于 <tx> 的方式。其长处是与切点表达式结合,功能强大。

    利用切点表达

    式,一个配置能够匹配多个方法,而基于@Transactional 的方式必须在每个须要使用事务的方法或者类上用 @Transactional 标注,虽然可能大多

    数事务的规则是一致的,可是对 @Transactional 而言,也无法重用。必须逐个指定。还有一方面。基于 @Transactional 的方式使用起来很easy明

    了,没有学习成本。开发者能够依据须要,任选当中一种使用。甚至也能够依据须要混合使用这两种方式。


    假设不是对遗留代码进行维护。则不建议再使用基于 TransactionInterceptor 以及基于 TransactionProxyFactoryBean 的声明式事务管理方式,可是,

    学习这两种方式很有利于对底层实现的理解,因为篇幅过长,我仅仅挑TransactionProxyFactoryBean来写

    利用 TransactionProxyFactoryBean 生成事务代理

    <?xml version="1.0" encoding="gb2312"?

    > <!-- Spring 配置文件的文件头,包括 DTD 等信息 --> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- 定义数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- 定义数据库驱动 --> <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property> <!-- 定义数据库 url--> <property name="url"><value>jdbc:mysql://localhost:3306/spring</value></property> <!-- 定义数据库用户名 --> <property name="username"><value>root</value></property> <!-- 定义数据库密码 --> <property name="password"><value>32147</value></property> </bean> <!-- 定义一个 hibernate 的 SessionFactory--> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <!-- 定义 SessionFactory 必须注入 DataSource--> <property name="dataSource"><ref local="dataSource"/></property> <property name="mappingResources"> <list> <!-- 以下用来列出全部的 PO 映射文件 --> <value>Person.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <!-- 此处用来定义 hibernate 的 SessionFactory 的属性: 不同数据库连接,启动时选择 create,update,create-drop--> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> </props> </property> </bean> <!-- 定义事务管理器,使用适用于 Hibernte 的事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <!-- HibernateTransactionManager bean 须要依赖注入一个 SessionFactory bean 的引用 --> <property name="sessionFactory"><ref local="sessionFactory"/></property> </bean> <!-- 配置事务拦截器 --> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <!-- 事务拦截器 bean 须要依赖注入一个事务管理器 --> <property name="transactionManager" ref="transactionManager"/> <property name="transactionAttributes"> <!-- 以下定义事务传播属性 --> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <!-- 定义 BeanNameAutoProxyCreator, 该 bean 是个 bean 后处理器,无需被引用。因此没有 id 属性 这个 bean 后处理器,依据事务拦截器为目标 bean 自己主动创建事务代理 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 指定对满足哪些 bean name 的 bean 自己主动生成业务代理 --> <property name="beanNames"> <!-- 以下是全部须要自己主动创建事务代理的 bean--> <list> <value>personDao</value> </list> <!-- 此处可添加其它须要自己主动创建事务代理的 bean--> </property> <!-- 以下定义 BeanNameAutoProxyCreator 所需的事务拦截器 --> <property name="interceptorNames"> <list> <value>transactionInterceptor</value> <!-- 此处可添加其它新的 Interceptor --> </list> </property> </bean> <!-- 定义 DAO Bean , 因为 BeanNameAutoProxyCreator 自己主动生成事务代理 --> <bean id="personDao" class="lee.PersonDaoHibernate"> <property name="sessionFactory"><ref local="sessionFactory"/></property> </bean> </beans>


     大部分情况下,每一个事务代理的事务属性大同小异,事务代理的实现类都是 TransactionProxyFactoryBean,事务代理 bean 都必须注入事务管理器。

    对于这样的情况, Spring 提供了 bean 与 bean 之间的继承,能够简化配置。将大部分的通用配置,配置成事务模板,而实际的事务代理 bean ,则继承

    事务模板。

    这样的配置方式能够降低部分配置代码,以下是採用继承的配置文件:

    <!-- 配置事务模板。模板 bean 被设置成 abstract bean ,保证不会被初始化 -->
    <bean id="txBase" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
    lazy-init="true" abstract="true">
    <!--   为事务模板注入事务管理器 -->
    <property name="transactionManager"><ref bean="transactionManager"/></property>
    <!--   设置事务属性 -->
            <property name="transactionAttributes">
    <props>
             <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
             <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
    </bean>
    <!--   实际的事务代理 bean-->
        <bean id="personDao" parent="txBase">
    <!--   採用嵌套 bean 配置目标 bean -->
    <property name="target">
        <bean class="lee.PersonDaoHibernate">
            <property name="sessionFactory"><ref local="sessionFactory"/></property>
         </bean>
    </property>
          </bean>

    这样的配置方式,相比前面直接採用 TransactionProxyFactoryBean 的事务代理配置方式。能够大大降低配置文件的代码量。每一个事务代理的

    配置都继承事务模板,无需重复指定事务代理的实现类,无需反复指定事务传播属性——当然。假设新的事务代理有额外的事务属性,也可指定自己的

    事务属性。此时。子 bean 的属性覆盖父 bean 的属性。当然每一个事务代理 bean 都必须配置自己的目标 bean ,这不可避免。

    上面的配置可看出,事

    务代理的配置依旧是增量式的,每一个事务代理都须要单独配置——尽管增量已经减少,但每一个事务代理都须要单独配置。


    结束语

    尽管我非常不愿意承认我对Spring事务的了解已经到此为止了,可是事实是如此。在结束之际。请同意我感谢开源社区的一篇文章。尽管里面内容写的乱

    七八糟,可是它是我思路的来源:http://www.open-open.com/lib/view/open1414310646012.html


    对Spring事务的总结例如以下:

    1. 基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务管理是Spring 提供的最原始的方式。通常我们不会这

    写,可是了解这样的方式对理解 Spring 事务管理的本质有非常大作用。

    2. 基于 TransactionTemplate 的编程式事务管理是对上一种方式的封装,使得编码更简单、清晰。

    对事务有着强烈的控制欲望的系统,能够选择这样的

    方式(我如今所在项目就是这样的实现方式)

    3. 基于 TransactionInterceptor 的声明式事务是 Spring 声明式事务的基础,通常也不建议使用这样的方式,可是与前面一样,了解这样的方式对理解 

    Spring 声明式事务有非常大作用。

    4. 基于 TransactionProxyFactoryBean 的声明式事务是上中方式的改进版本号,简化的配置文件的书写,这是Spring 早期推荐的声明式事务管理方式,

    可是在 Spring 2.0 中已经不推荐了

    5. 基于 <tx> 和 <aop> 命名空间的声明式事务管理是眼下推荐的方式,其最大特点是与 Spring AOP 结合紧密,能够充分利用切点表达式的强大支持,

    使得管理事务更加灵活。

    6. 基于 @Transactional 的方式将声明式事务管理简化到了极致。开发者仅仅需在配置文件里加上一行启用相关后处理 Bean 的配置,然后在须要实施

    事务管理的方法或者类上使用 @Transactional 指定事务规则就可以实现事务管理。并且功能也不必其它方式逊色


  • 相关阅读:
    ASSIC码对照表
    IIS注册 net环境
    Remoting1
    WinCE API
    【可下载】C#中关于zip压缩解压帮助类的封装
    【原创,提供下载】winfrom 打印表格,字符串的封装
    一个可编辑div中粘贴内容时过滤掉粘贴内容的一些特殊的样式或者标签
    限制一个文本框只能输入数字以及限制最大只能输入的数字
    文本框中有默认的文字,写获取焦点和失去焦点的文字显示与消失的效果
    鼠标滑过图片变大,移开还原大小的动画效果
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/7289651.html
Copyright © 2011-2022 走看看