全面分析 Spring 的编程式事务管理及声明式事务管理

jopen 9年前

关于本教程

本教程将深切讲授 Spring 庞杂而丁壮夜的事务治理功用,包括编程式事务和声明式事务。经由进程对本教程的进修,您将可以理解 Spring 事务治理的实质,并无邪运用之。

先决前提

本教程假定您已掌控了 Java 根蒂根抵常识,并对 Spring 有一定意见。您还需求具有根抵的事务治理的常识,好比:事务的界说,隔离级其他概念,等等。本文将直接行使这些概念而不做具体正文。其他,您最好掌控数据库的根蒂根抵常识,虽然这不是必需。

零星需求

要实行这份教程中的对象和示例,硬件设置配备铺排需求为:至多带有 512MB 内存(举荐 1GB)的零星。需求安装以下软件:

  • Sun JDK 5.0 或更新版本或 IBM Developer Kit for the Java 5 platform 版本。
  • Spring framework 2.5。本教程附带的示例代码已在 Spring 2.5.6 上测试过。
  • MySQL 5.0 或更新版本。

Spring 事务属性剖析

事务治理对企业运用而言至关主要。它担保了用户的每次操作都是靠得住的,即便泛起了异常的接见情形,也不至于损坏后台数据的完整性。就像银行的自助 取款机,常日都能正常为客户干事,然则也难免碰着操作进程傍边机械溘然出缺点的情形,此时,事务就必需确保出缺点前对账户的操作不生效,就像用户适才完整 没有行使过取款机一样,以担保用户和银行的优点都不受损丢失落。

在 Spring 中,事务是经由进程 TransactionDefinition 接口来界说的。该接口包括与事务属性有关的方法。具体如清单1所示:

清单1. TransactionDefinition 接口中界说的次要方法
public interface TransactionDefinition{  int getIsolationLevel();  int getPropagationBehavior();  int getTimeout();  boolean isReadOnly();  }

也许你会希奇,为什么接口只供应了获得属性的方法,而没有供应相关设置属性的方法。其实事理很庞杂,事务属性的设置完整是轨范员掌握的,是以轨范员 可以自界说任何设置属性的方法,而且留存属性的字段也没有任何要求。独一的要求的是,Spring 中止事务操作的时辰,经由进程挪用以上接口供给的方法必需可以前旧事务相关的属性取值。

事务隔离级别

隔离级别是指若干个并发的事务之间的隔离水平。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 中的留存点(SavePoint)的概念,那嵌套事务就很随意疏忽理解了,其实嵌套的子事务就是留存点的一个运用,一个事务中可以包括多个留存点,每一个 嵌套子事务。其他,内部事务的回滚也会致使嵌套子事务的回滚。

事务超时

所谓事务超时,就是指一个事务所准许实行的最长时辰,假定跨越该时辰限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来泄漏表现超不时辰,其单元是秒。

事务的只读属性

事务的只读属性是指,对事务性成本中止只读操作或是读写操作。所谓事务性成本就是指那些被事务治理的成本,好比数据源、 JMS 成本,和自界说的事务性成本等等。假定一定只对事务性成本中止只读操作,那末我们可以将事务符号为只读的,以提高事务处置责罚的功效。在 TransactionDefinition 中以 boolean 类型来泄漏表现该事务能否是只读。

事务的回滚划定礼貌

常日情形下,假定在事务中抛出了未搜检异常(连续自 RuntimeException 的异常),则默许将回滚事务。假定没有抛出任何异常,或抛出了已搜检异常,则仍然提交事务。这常日也是除夜多半垦荒者进展的处置责罚体式格式,也是 EJB 中的默许处置责罚体式格式。然则,我们可以凭证需求工资掌握事务在抛出某些未搜检异常时任然提交事务,或在抛出某些已搜检异常时回滚事务。


Spring 事务治理 API 剖析

Spring 框架中,触及到事务治理的 API 除夜约有100个旁边,个中最主要的有三个:TransactionDefinition、PlatformTransactionManager、 TransactionStatus。所谓事务治理,其实就是“依照给定的事务划定礼貌来实行提交或回滚操作”。“给定的事务划定礼貌”就是用 TransactionDefinition 泄漏表现的,“依照……来实行提交或回滚操作”就是用 PlatformTransactionManager 来泄漏表现,而 TransactionStatus 用于泄漏表现一个运转着的事务的形态。打一个不适合的歧,TransactionDefinition 与 TransactionStatus 的关系就像轨范和进程的关系。

TransactionDef…

该接口在后面已引见过,它用于界说一个事务。它包括了事务的静态属性,好比:事务流传举动、超不时辰等等。Spring 为我们供应了一个默许的完成类:DefaultTransactionDefinition,该类适用于除夜多半情形。假定该类不能知足需求,可以经由进 程完成 TransactionDefinition 接口来完成本人的事务界说。

PlatformTrans…

PlatformTransactionManager 用于实行具体的事务操作。接口界说如清单2所示:

清单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 的次要完成类除夜致以下:

  • DataSourceTransactionManager:适用于行使JDBC和iBatis中止数据经久化操作的情形。
  • HibernateTransactionManager:适用于行使Hibernate中止数据经久化操作的情形。
  • JpaTransactionManager:适用于行使JPA中止数据经久化操作的情形。
  • 其他还有JtaTransactionManager 、JdoTransactionManager、JmsTransactionManager等等。

假定我们行使JTA中止事务治理,我们可以经由进程 JNDI 和 Spring 的 JtaTransactionManager 来获得一个容器治理的 DataSource。JtaTransactionManager 不需求晓得 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 的人都晓得,我们需求在代码中显式挪用beginTransaction()、commit()、rollback()等事务治理相关的方法,这就是编程 式事务治理。经由进程 Spring 供应的事务治理 API,我们可以在代码中无邪掌握事务的实行。在底层,Spring 仍然将事务操作请托给底层的经久化框架来实行。

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

凭证PlatformTransactionManager、TransactionDefinition 和 TransactionStatus 三个焦点接口,我们完整可以经由进程编程的体式格式来中止事务治理。示例代码如清单4所示:

清单4. 基于底层 API 的事务治理示例代码
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;  }  }

呼应的设置配备铺排文件如清单5所示:

清单5. 基于底层API的事务治理示例设置配备铺排文件
<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.getTransaction(…) 方法即可启动一个事务。树立并启动了事务之后,即可以最先编写营业逻辑代码,然后在适合的地方实行事务的提交或回滚。

基于 TransactionTemplate 的编程式事务治理

经由进程后面的示例可以发明,这类事务治理体式格式很随意疏忽理解,但使人头疼的是,事务治理的代码散落在营业逻辑代码中,损坏了原有代码的条感 性,而且每一个营业方法都包括了相反的启动事务、提交/回滚事务的样板代码。幸而,Spring 也意想到了这些,并供应了简化的方法,这就是 Spring 在数据接见层异经罕有的模板回调方法。如清单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;  }  });  }  }

呼应的XML设置配备铺排以下:

清单 7. 基于 TransactionTemplate 的事务治理示例设置配备铺排文件
<bean id="bankService"  class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">  <property name="bankDao" ref="bankDao"/>  <property name="transactionTemplate" ref="transactionTemplate"/>  </bean>

TransactionTemplate 的 execute() 方法有一个 TransactionCallback 类型的参数,该接口中界说了一个 doInTransaction() 方法,常日我们以匿名内部类的体式格式完成 TransactionCallback 接口,并在其 doInTransaction() 方法中书写营业逻辑代码。这里可以行使默许的事务提交和回滚划定礼貌,这样在营业代码中就不需求显式挪用任何事务治理的 API。doInTransaction() 方法有一个TransactionStatus 类型的参数,我们可以在方法的任何位置挪用该参数的 setRollbackOnly() 方法将事务标识为回滚的,以实行事务回滚。

凭证默许划定礼貌,假定在实行回调方法的进程傍边抛出了未搜检异常,或显式挪用了TransacationStatus.setRollbackOnly() 方法,则回滚事务;假定事务实行完成或抛出了 checked 类型的异常,则提交事务。

TransactionCallback 接口有一个子接口 TransactionCallbackWithoutResult,该接口中界说了一个 doInTransactionWithoutResult() 方法,TransactionCallbackWithoutResult 接口次要用于事务进程傍边不需求前往值的情形。虽然,对不需求前往值的情形,我们仍然可以行使 TransactionCallback 接口,并在方法中前往随意率性值即可。


声明式事务治理

Spring 的声明式事务治理概述

Spring 的声明式事务治理在底层是竖立在 AOP 的根蒂根抵之上的。其实质是对方法前落先行隔绝,然后在目的方法最先之前树立或介入一个事务,在实行完目的方法之后凭证实行情形提交或回滚事务。

声明式事务最除夜的优点就是不需求经由进程编程的体式格式治理事务,这样就不需求在营业逻辑代码中搀杂事务治理的代码,只需在设置配备铺排文件中做 相关的事务划定礼貌声明(或经由进程等价的基于标注的体式格式),即可以将事务划定礼貌运用到营业逻辑中。因为事务治理本人就是一个范例的横切逻辑,恰是 AOP 的用武之地。Spring 垦荒团队也意想到了这一点,为声明式事务供应了庞杂而丁壮夜的支持。

声明式事务治理曾是 EJB 引以为傲的一个亮点,现在 Spring 让 POJO 在事务治理方面也具有了和 EJB 一样的待遇,闪垦荒人员在 EJB 容器之外也用上了丁壮夜的声明式事务治理功用,此次要得益于 Spring 依托注入容器和 Spring AOP 的支持。依托注入容器为声明式事务治理供应了根蒂根抵举动装备,使得 Bean 对 Spring 框架而言是可治理的;而 Spring AOP 则是声明式事务治理的直接完成者,这一点经由进程清单8可以看出来。

常日情形下,笔者剧烈建议在垦荒中行使声明式事务,不只因为其庞杂,更主假定因为这样使得纯营业代码不被净化,极除夜随意后期的代码珍重。

和编程式事务比照,声明式事务独一缺少地方是,后者的最细粒度只能浸染到方法级别,没法做到像编程式事务那样可以浸染到代码块级别。然则即便有这样的需求,也存在许多变通的方法,好比,可以将需求中止事务治理的代码块自力为方法等等。

上面就来看看 Spring 为我们供应的声明式事务治理功用。

基于 TransactionInter… 的声明式事务治理

最初,Spring 供应了 TransactionInterceptor 类来实行声明式事务治理功用。先看清单8的设置配备铺排文件:

清单 8. 基于 TransactionInterceptor 的事务治理示例设置配备铺排文件
<beans...>  ......  <bean id="transactionInterceptor"  class="org.springframework.transaction.interceptor.TransactionInterceptor">  <property name="transactionManager" ref="transactionManager"/>  <property name="transactionAttributes">  <props>  <prop key="transfer">PROPAGATION_REQUIRED</prop>  </props>  </property>  </bean>  <bean id="bankServiceTarget"  class="footmark.spring.core.tx.declare.origin.BankServiceImpl">  <property name="bankDao" ref="bankDao"/>  </bean>  <bean id="bankService"  class="org.springframework.aop.framework.ProxyFactoryBean">  <property name="target" ref="bankServiceTarget"/>  <property name="interceptorNames">  <list>  <idref bean="transactionInterceptor"/>  </list>  </property>  </bean>  ......  </beans>

首先,我们设置配备铺排了一个 TransactionInterceptor 来界说相关的事务划定礼貌,他有两个次要的属性:一个是 transactionManager,用来指定一个事务治理器,并将具体事务相关的操作请托给它;其他一个是 Properties 类型的 transactionAttributes 属性,它次要用来界说事务划定礼貌,该属性的每一个键值对中,键指定的是方法名,方法名可以行使通配符,而值就泄漏表现呼应方法的所运用的事务属性。

指定事务属性的取值有较庞杂的划定礼貌,这在 Spring 中算得上是一件让人头疼的事。具体的书写划定礼貌以下:

流传举动 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,致使回滚的异常]
  • 流传举动是独一必需设置的属性,其他都可以疏忽,Spring为我们供应了合理的默许值。
  • 流传举动的取值必需以“PROPAGATION_”开首,具体包括:PROPAGATION_MANDATORY、 PROPAGATION_NESTED、PROPAGATION_NEVER、PROPAGATION_NOT_SUPPORTED、 PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_SUPPORTS,共七种取 值。
  • 隔离级其他取值必需以“ISOLATION_”开首,具体包括:ISOLATION_DEFAULT、 ISOLATION_READ_COMMITTED、ISOLATION_READ_UNCOMMITTED、 ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE,共五种取值。
  • 假定事务是只读的,那末我们可以指定只读属性,行使“readOnly”指定。否则我们不需求设置该属性。
  • 超时属性的取值必需以“TIMEOUT_”开首,后面跟一个int类型的值,泄漏表现超不时辰,单元是秒。
  • 不影响提交的异常是指,即便事务中抛出了这些类型的异常,事务任然正常提交。必需在每一个异常的名字后面加上“+”。异常的名字可所以类名的一部份。好比“+RuntimeException”、“+tion”等等。
  • 致使回滚的异常是指,当事务中抛出这些类型的异常时,事务将回滚。必需在每一个异常的名字后面加上“-”。异常的名字可所以类名的悉数或部份,好比“-RuntimeException”、“-tion”等等。

以下是两个示例:

<property name="*Service">  PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,  +AbcException,+DefException,-HijException  </property>

以上表达式泄漏表现,针对一切方法名以 Service 收尾的方法,行使 PROPAGATION_REQUIRED 事务流传举动,事务的隔离级别是 ISOLATION_READ_COMMITTED,超不时辰为20秒,当事务抛出 AbcException 或 DefException 类型的异常,则仍然提交,当抛出 HijException 类型的异常时必需回滚事务。这里没有指定”readOnly”,泄漏表现事务不是只读的。

<property name="test">PROPAGATION_REQUIRED,readOnly</property>

以上表达式泄漏表现,针对一切方法名为 test 的方法,行使 PROPAGATION_REQUIRED 事务流传举动,而且该事务是只读的。除此之外,其他的属性均行使默许值。好比,隔离级别和超不时辰行使底层事务性成本的默许值,而且当发生发火未搜检异 常,则回滚事务,发生发火已搜检异常则仍提交事务。

设置配备铺排好了 TransactionInterceptor,我们还需求设置配备铺排一个 ProxyFactoryBean 来组装 target 和advice。这也是范例的 Spring AOP 的做法。经由进程 ProxyFactoryBean 生成的署理类就是织入了事务治理逻辑后的目的类。至此,声明式事务治理就算是完成了。我们没有对营业代码中止任何操作,一切设置均在设置配备铺排文件中完 成,这就是声明式事务的最除夜优点。

基于 TransactionProxy… 的声明式事务治理

后面的声明式事务虽然好,然则却存在一个异常恼人的成就:设置配备铺排文件太多。我们必需针对每一个目的对象设置配备铺排一个 ProxyFactoryBean;其他,虽然可以经由进程父子 Bean 的体式格式来复用 TransactionInterceptor 的设置配备铺排,然则理想的复用几率也不高;这样,加上目的对象本人,每一个营业类可以需求对应三个 <bean/> 设置配备铺排,跟着营业类的增多,设置配备铺排文件将会变得越来越重除夜,治理设置配备铺排文件又成了成就。

为了减缓这个成就,Spring 为我们供应了 TransactionProxyFactoryBean,用于将TransactionInterceptor 和 ProxyFactoryBean 的设置配备铺排合二为一。如清单9所示:

清单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>

如斯一来,设置配备铺排文件与先前比照简化了许多。我们把这类设置配备铺排体式格式称为 Spring 经典的声明式事务治理。信任在晚期行使 Spring 的垦荒人员对这类设置配备铺排声明式事务的体式格式一定异常熟习。

然则,显式为每一个营业类设置配备铺排一个 TransactionProxyFactoryBean 的做法将使得代码显得过于机械,为此我们可以行使自动树立署理的体式格式来将其简化,行使自动树立署理是纯 AOP 常识,请读者参考相关文档,不在此赘述。

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

后面两种声明式事务设置配备铺排体式格式奠基了 Spring 声明式事务治理的基石。在此根蒂根抵上,Spring 2.x 引入了 <tx> 命名空间,连络行使 <aop> 命名空间,带给垦荒人员设置配备铺排声明式事务的全新体验,设置配备铺排变得加倍庞杂和无邪。其他,得益于 <aop> 命名空间的切点表达式支持,声明式事务也变得加倍丁壮夜。

如清单10所示:

清单10. 基于 <tx> 的事务治理示例设置配备铺排文件
<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>

假定默许的事务属性就可以知足要求,那末代码简化为如清单 11 所示:

清单 11. 简化后的基于 <tx> 的事务治理示例设置配备铺排文件
<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">  <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 的体式格式行使起来异常庞杂清晰了了,没有进修成本。垦荒人员可以凭证需求,任选个中一种行使,甚至也可以凭证需求夹杂行使这两种体式格式。

假定不是对遗留代码中止珍重,则不建议再行使基于 TransactionInterceptor 和基于TransactionProxyFactoryBean 的声明式事务治理体式格式,然则,进修这两种体式格式异常无益于对底层完成的理解。

虽然上面共枚举了四种声明式事务治理体式格式,然则这样的划分只是为了便于理解,其实后台的完成体式格式是一样的,只是用户行使的体式格式不合而已。


停止语

本教程的常识点除夜致总结以下:

  • 基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务治理是 Spring 供应的最原始的体式格式,常日我们不会这么写,然则意见这类体式格式对理解 Spring 事务治理的实质有很鸿文用。
  • 基于 TransactionTemplate 的编程式事务治理是对上一种体式格式的封装,使得编码更庞杂、了了。
  • 基于 TransactionInterceptor 的声明式事务是 Spring 声明式事务的根蒂根抵,常日也不建议行使这类体式格式,然则与后面一样,意见这类体式格式对理解 Spring 声明式事务有很鸿文用。
  • 基于 TransactionProxyFactoryBean 的声明式事务是上中体式格式的改良版本,简化的设置配备铺排文件的书写,这是 Spring 晚期举荐的声明式事务治理体式格式,然则在 Spring 2.0 中已不举荐了。
  • 基于 <tx> 和 <aop> 命名空间的声明式事务治理是今朝举荐的体式格式,其最除夜特色是与 Spring AOP 连络慎密,可以富余行使切点表达式的丁壮夜支持,使得治理事务加倍无邪。
  • 基于 @Transactional 的体式格式将声明式事务治理简化到了极致。垦荒人员只需在设置配备铺排文件中加上一行启用相关后处置责罚 Bean 的设置配备铺排,然后在需求实行事务治理的方法或类下行使 @Transactional 指定事务划定礼貌即可完成事务治理,而且功用也没需求其他体式格式减色。