天天看点

【Spring】Spring Framework Reference Documentation中文版13

Part V. Data Access

数据访问

This part of the reference documentation is concerned with data access and the interaction between the data access layer and the business or service layer.

这部分的参考文档关注于数据访问和数据访问层和业务层的连接。

Spring’s comprehensive transaction management support is covered in some detail, followed by thorough coverage of the various data access frameworks and technologies that the Spring Framework integrates with.

spring复杂的事务管理支持会介绍一部分,覆盖不同数据访问框架和技术集成在spring中。

    Chapter 17, Transaction Management

章节17,事务管理

    Chapter 18, DAO support

章节18,DAO支持

    Chapter 19, Data access with JDBC

章节19,使用JDBC访问数据

    Chapter 20, Object Relational Mapping (ORM) Data Access

章节20,对象关系映射数据访问

    Chapter 21, Marshalling XML using O/X Mappers

章节21,使用O/X映射来整理XML

17. Transaction Management

事务管理0

17.1 Introduction to Spring Framework transaction management

介绍spring框架的事务管理

Comprehensive transaction support is among the most compelling reasons to use the Spring Framework. The Spring Framework provides a consistent abstraction for transaction management that delivers the following benefits:

复杂的事务支持被使用在spring的框架中。spring框架提供了一致的抽象对于事务管理提供了以下的益处:

    Consistent programming model across different transaction APIs such as Java Transaction API (JTA), JDBC, Hibernate, Java Persistence API (JPA), and Java Data Objects (JDO).

一致的编程模型跨越不同的事务API例如Java事务API、JDBC、Hibernate、Java持久化API和Java数据object。

    Support for declarative transaction management.

支持声明式的事务管理。

    Simpler API for programmatic transaction management than complex transaction APIs such as JTA.

简单的API用于编程事务管理,对于复杂的事务API如JTA。

    Excellent integration with Spring’s data access abstractions.

优秀的集成来自spring的数据访问抽象

The following sections describe the Spring Framework’s transaction value-adds and technologies. (The chapter also includes discussions of best practices, application server integration, and solutions to common problems.)

下面的章节描述了spring的框架事务价值增值和技术。(章节中也讨论了最佳案例,应用服务集成和通常问题的解决。)

    Advantages of the Spring Framework’s transaction support model describes why you would use the Spring Framework’s transaction abstraction instead of EJB Container-Managed Transactions (CMT) or choosing to drive local transactions through a proprietary API such as Hibernate.

spring框架事务管理模型的优点描述了为什么你应该使用spring框架的事务抽象代替EJB容器管理事务或选择驾驭本地事务通过适当的API例如Hibernate。

    Understanding the Spring Framework transaction abstraction outlines the core classes and describes how to configure and obtain DataSource instances from a variety of sources.

了解spring框架的事务抽象在核心类之外并且描述如何配置和获取数据源实例来自不同的源。

    Synchronizing resources with transactions describes how the application code ensures that resources are created, reused, and cleaned up properly.

事务下的同步资源描述了应用代码如何保证资源的创建、重用和清理。

    Declarative transaction management describes support for declarative transaction management.

声明式事务管理描述了声明式事务管理的支持。

    Programmatic transaction management covers support for programmatic (that is, explicitly coded) transaction management.

编程事务管理包括支持编程(也就是明确编码)事务管理

    Transaction bound event describes how you could use application events within a transaction.

事务绑定事件描述你如何可以使用应用事件配合事务。

17.2 Advantages of the Spring Framework’s transaction support model

spring框架事务支持模型的优点

Traditionally, Java EE developers have had two choices for transaction management: global or local transactions, both of which have profound limitations. Global and local transaction management is reviewed in the next two sections, followed by a discussion of how the Spring Framework’s transaction management support addresses the limitations of the global and local transaction models.

传统情况下,JavaEE开发者有两个选择对于事务管理:全局或本地事务,每一种都有一定的限制。全局和本地事务管理在下面两节中介绍,下面讨论一下spirng框架事务管理支持是如何突破全局和本地事务管理的限制的。

17.2.1 Global transactions

全局事务

Global transactions enable you to work with multiple transactional resources, typically relational databases and message queues. The application server manages global transactions through the JTA, which is a cumbersome API to use (partly due to its exception model). Furthermore, a JTA UserTransaction normally needs to be sourced from JNDI, meaning that you also need to use JNDI in order to use JTA. Obviously the use of global transactions would limit any potential reuse of application code, as JTA is normally only available in an application server environment.

全局事务允许你使用多个事务资源一同操作,通常是关系型数据库和消息队列。应用服务器管理全局事务通过JTA,会使用到十分笨重的API(一部分由于他的异常模型)。更进一步,JTA的用户事务通常需要使用JNDI,意味着你需要JNDI来使用JTA。明显的全局事务的使用限制一些潜在的应用代码的重用,作为JTA只能在应用服务器环境中可用。

Previously, the preferred way to use global transactions was via EJB CMT (Container Managed Transaction): CMT is a form of declarative transaction management (as distinguished from programmatic transaction management). EJB CMT removes the need for transaction-related JNDI lookups, although of course the use of EJB itself necessitates the use of JNDI. It removes most but not all of the need to write Java code to control transactions. The significant downside is that CMT is tied to JTA and an application server environment. Also, it is only available if one chooses to implement business logic in EJBs, or at least behind a transactional EJB facade. The negatives of EJB in general are so great that this is not an attractive proposition, especially in the face of compelling alternatives for declarative transaction management.

以前优先的方法是使用全局事务是EJB的CMT(容器管理事务):CMT是一种声明式事务管理的形式(和编程式事务管理区分)。EJB CMT取消了事务相关的JNDI查找,尽管使用EJB本身需要使用JNDI。他取消了大部分不需要书写java代码来控制事务。重要的缺点是CMT绑定到了JTA和一个应用服务器环境。并且只能选择EJB来实现业务逻辑或至少使用传统的EJB模式。EJB的缺点是太过庞杂并且不是很吸引人使用,尤其是面对强制替换声明式的事务管理。

17.2.2 Local transactions

本地事务

Local transactions are resource-specific, such as a transaction associated with a JDBC connection. Local transactions may be easier to use, but have significant disadvantages: they cannot work across multiple transactional resources. For example, code that manages transactions using a JDBC connection cannot run within a global JTA transaction. Because the application server is not involved in transaction management, it cannot help ensure correctness across multiple resources. (It is worth noting that most applications use a single transaction resource.) Another downside is that local transactions are invasive to the programming model.

本地事务是基于特定资源的,例如一个事务和JDBC连接结合在一起。本地事务可能易于使用,但是有很多显著的缺点:他们不能跨多个事务资源。例如,使用JDBC来管理事务不能运行一个全局的JTA事务。因为应用服务器并没有在事务管理中,不能确保跨多个资源的正确性。(但是不需要担心因为大部分应用使用一个单一的事务资源。)另外就是本地事务对编程模型有一定的侵入性。

17.2.3 Spring Framework’s consistent programming model

spring框架的一致编程模型

Spring resolves the disadvantages of global and local transactions. It enables application developers to use a consistent programming model in any environment. You write your code once, and it can benefit from different transaction management strategies in different environments. The Spring Framework provides both declarative and programmatic transaction management. Most users prefer declarative transaction management, which is recommended in most cases.

spring综合了全局事务和本地事务。允许应用开发者在任何环境中都使用一致的编程模型。你只要书写一次代码,就可以在不同的环境中管理事务。spring框架提供了声明式和编程式的事务管理。大部分用户倾向于使用声明式的事务管理,并且也在大部分情况下被推荐使用。

With programmatic transaction management, developers work with the Spring Framework transaction abstraction, which can run over any underlying transaction infrastructure. With the preferred declarative model, developers typically write little or no code related to transaction management, and hence do not depend on the Spring Framework transaction API, or any other transaction API.

使用编程式事务管理,开发者使用spring框架的事务抽象,可以运行在任何基础的事务基础设施。根据更好的声明式模型,开发者通常只要书写很少的代码或基本不写代码就可以实现事务管理,并且不需要依赖spring框架的事务API或其他事务API。

Do you need an application server for transaction management?

你希望一个应用服务器来管理事务吗?

The Spring Framework’s transaction management support changes traditional rules as to when an enterprise Java application requires an application server.

spring框架的事务管理支持改变传统的规则当企业Java应用需要一个应用服务器时。

In particular, you do not need an application server simply for declarative transactions through EJBs. In fact, even if your application server has powerful JTA capabilities, you may decide that the Spring Framework’s declarative transactions offer more power and a more productive programming model than EJB CMT.

特定情况下,你不需要应用服务器通过EJB来声明事务。实际上,如果你的应用服务器有强大的JTA能力,你可以决定spring框架声明式事务提供更强大和更具有生产力的编程模型通过EJB的CMT。

Typically you need an application server’s JTA capability only if your application needs to handle transactions across multiple resources, which is not a requirement for many applications. Many high-end applications use a single, highly scalable database (such as Oracle RAC) instead. Standalone transaction managers such as Atomikos Transactions and JOTM are other options. Of course, you may need other application server capabilities such as Java Message Service (JMS) and Java EE Connector Architecture (JCA).

通常你需要一个应用服务器的JTA能力如果你的应用需要处理事务跨多个资源,不需要多个应用。许多高端的应用使用单一、大规模数据库(例如Oracle RAC)作为替代。单独的事务管理例如Atomikos事务和JTOM就是其他的选择。当然,你可能需要其他的应用服务器能力例如JMS和JavaEE容器架构。

The Spring Framework gives you the choice of when to scale your application to a fully loaded application server. Gone are the days when the only alternative to using EJB CMT or JTA was to write code with local transactions such as those on JDBC connections, and face a hefty rework if you need that code to run within global, container-managed transactions. With the Spring Framework, only some of the bean definitions in your configuration file, rather than your code, need to change.

spring框架给了你选择当你的应用可以全部加载到应用服务器中。选择使用EJB的CMT或JTA写代码来管理本地事务例如通过JDBC连接和如果你的代码使用了全局的容器管理事务将面对复杂的工作量的时代已经过去了。使用spring框架,只有一些你配置文件中的bean的定义而不是你代码会需要改变。

17.3 Understanding the Spring Framework transaction abstraction

理解spring框架的事务管理抽象

The key to the Spring transaction abstraction is the notion of a transaction strategy. A transaction strategy is defined by the org.springframework.transaction.PlatformTransactionManager interface:

spring事务管理抽象的关键是对事务策略的概念。一个事务策略被定义在org.springframework.transaction.PlatformTransactionManager接口中:

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(

            TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;

}

This is primarily a service provider interface (SPI), although it can be used programmatically from your application code. Because PlatformTransactionManager is an interface, it can be easily mocked or stubbed as necessary. It is not tied to a lookup strategy such as JNDI. PlatformTransactionManager implementations are defined like any other object (or bean) in the Spring Framework IoC container. This benefit alone makes Spring Framework transactions a worthwhile abstraction even when you work with JTA. Transactional code can be tested much more easily than if it used JTA directly.

这是主要的一个服务提供接口,因此可以用于编程你的代码。因为PlatformTransactionManager是一个接口,他可以简单的模拟或继承。如果不想和查找机制绑定例如JNDI。PlatformTransactionManager实现被定义就像其他的object在spring框架的IOC容器中。这也使得spring框架事务在你使用JTA时也可以用。事务代码可以简单的测试如果你直接使用JTA的话。

Again in keeping with Spring’s philosophy, the TransactionException that can be thrown by any of the PlatformTransactionManager interface’s methods is unchecked (that is, it extends the java.lang.RuntimeException class). Transaction infrastructure failures are almost invariably fatal. In rare cases where application code can actually recover from a transaction failure, the application developer can still choose to catch and handle TransactionException. The salient point is that developers are not forced to do so.

为了保证spring的哲学,TransactionException可以被任何PlatformTransactionManager接口方法抛出并且没有被检查(也就是,他继承了java.lang.RuntimeException类)。事务基础架构失败是致命的。基本上应用代码不会遇到需要从事务失败中恢复的情况,应用开发者依然选择捕获和处理TransactionException。但是没有强制开发者这么做。

The getTransaction(..) method returns a TransactionStatus object, depending on a TransactionDefinition parameter. The returned TransactionStatus might represent a new transaction, or can represent an existing transaction if a matching transaction exists in the current call stack. The implication in this latter case is that, as with Java EE transaction contexts, a TransactionStatus is associated with a thread of execution.

getTransaction方法返回一个TransactionStatus,依赖一个TransactionDefinition参数。返回的TransactionStatus可以代表一个新的事务或可以代表一个已经存在的事务如果一个匹配的事务存在于当前的调用栈中。在这个词的隐含含义是在JavaEE事务上下文,一个TransactionStatus和执行线程相关联。

The TransactionDefinition interface specifies:

TransactionDefinition接口指定:

    Isolation: The degree to which this transaction is isolated from the work of other transactions. For example, can this transaction see uncommitted writes from other transactions?

隔离:事务和其他事务的相关度。例如,这个事务是否可以看到其他未提交的事务?

    Propagation: Typically, all code executed within a transaction scope will run in that transaction. However, you have the option of specifying the behavior in the event that a transactional method is executed when a transaction context already exists. For example, code can continue running in the existing transaction (the common case); or the existing transaction can be suspended and a new transaction created. Spring offers all of the transaction propagation options familiar from EJB CMT. To read about the semantics of transaction propagation in Spring, see Section 17.5.7, “Transaction propagation”.

传播:通常,所有的代码在一个事务范围内执行将在那个事务。然而,你有一个选项定义事件的行为就是一个事务方法在事务上下文已经存在的情况下执行。例如,代码可以继续执行在一个已经存在的事务中(通常情况);或者已经存在的事务可以被挂起然后创建一个新的事务。spring提供了所有的事务传播选项和EJB的CMT相似。为了了解spring中关于事务传播的语义,见17.5.7“事务传播”。

    Timeout: How long this transaction runs before timing out and being rolled back automatically by the underlying transaction infrastructure.

超时:这个事务会运行多久后超时和被自动回滚通过事务的管理。

    Read-only status: A read-only transaction can be used when your code reads but does not modify data. Read-only transactions can be a useful optimization in some cases, such as when you are using Hibernate.

只读状态:一个只读事务可以被使用当你的代码读数据但是不修改数据。只读事务在一些情况下可以很有用,例如你使用Hibernate。

These settings reflect standard transactional concepts. If necessary, refer to resources that discuss transaction isolation levels and other core transaction concepts. Understanding these concepts is essential to using the Spring Framework or any transaction management solution.

这些设置代码标准的事务概念。如果必须,参考事务隔离级别和其他事务的章节。了解这些内容是有必要的在使用spring框架或其他事务管理解决方案的时候。

The TransactionStatus interface provides a simple way for transactional code to control transaction execution and query transaction status. The concepts should be familiar, as they are common to all transaction APIs:

TransactionStatus接口提供了一个简单的方式对于事务代码来管理事务执行和查询事务状态。内容是相似的,并且对于所有事务API是通用的:

public interface TransactionStatus extends SavepointManager {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();

}

Regardless of whether you opt for declarative or programmatic transaction management in Spring, defining the correct PlatformTransactionManager implementation is absolutely essential. You typically define this implementation through dependency injection.

不管你是否选择声明式或编程式事务管理在spring中,定义正确的PlatformTransactionManager实现是非常有必要的。你通常使用依赖注入来定义实现。

PlatformTransactionManager implementations normally require knowledge of the environment in which they work: JDBC, JTA, Hibernate, and so on. The following examples show how you can define a local PlatformTransactionManager implementation. (This example works with plain JDBC.)

PlatformTransactionManager实现通常需要获得她们需要工作的环境:JDBC、JTA、Hibernate等等。下面的例子展示了你如何定义一个本地的PlatformTransactionManager实现。(这个例子使用了普通的JDBC)

You define a JDBC DataSource

你定义一个JDBC数据源

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

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

The related PlatformTransactionManager bean definition will then have a reference to the DataSource definition. It will look like this:

相关的PlatformTransactionManager的bean定义有引用数据源定义。如下:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

</bean>

If you use JTA in a Java EE container then you use a container DataSource, obtained through JNDI, in conjunction with Spring’s JtaTransactionManager. This is what the JTA and JNDI lookup version would look like:

如果你使用JTA在JavaEE容器并且你使用了一个容器数据源,通过JNDI获取,可以配合spring的JtaTransactionManager。下面是JTA和JNDI查找的案例:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:jee="http://www.springframework.org/schema/jee"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/jee

        http://www.springframework.org/schema/jee/spring-jee.xsd">

    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>

    <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

    <!-- other <bean/> definitions here -->

</beans>

The JtaTransactionManager does not need to know about the DataSource, or any other specific resources, because it uses the container’s global transaction management infrastructure.

JtaTransactionManager不需要知道数据源或其他特定的资源,因为他使用了容器的全局事务管理架构。

[Note]

注意

The above definition of the dataSource bean uses the <jndi-lookup/> tag from the jee namespace. For more information on schema-based configuration, see Chapter 41, XML Schema-based configuration, and for more information on the <jee/> tags see the section entitled Section 41.2.3, “the jee schema”.

上面有关dataSource的bean定义使用了<jndi-lookup/>标签来自jee命名空间。关于更多信息有关基于schema配置见章节41,XML基于schema的配置另外关于<jee/>标签的更多信息见章节41.2.3“jee schema”。

You can also use Hibernate local transactions easily, as shown in the following examples. In this case, you need to define a Hibernate LocalSessionFactoryBean, which your application code will use to obtain Hibernate Session instances.

你也可以简单使用Hibernate本地事务,就像下面的例子一样。在这个例子中,你需要定义一个Hibernate的LocalSessionFactoryBean,你的应用代码用于获得Hibernate的会话实例。

The DataSource bean definition will be similar to the local JDBC example shown previously and thus is not shown in the following example.

数据源bean定义将和之前展示的本地的JDBC例子相似并且不会再下面的例子中展现。

[Note]

注意

If the DataSource, used by any non-JTA transaction manager, is looked up via JNDI and managed by a Java EE container, then it should be non-transactional because the Spring Framework, rather than the Java EE container, will manage the transactions.

在数据源中,不使用JTA的事务管理,通过JNDI来查找并通过JavaEE容器来管理,他是非事务的应为spring框架而不是JavaEE容器将管理事务。

The txManager bean in this case is of the HibernateTransactionManager type. In the same way as the DataSourceTransactionManager needs a reference to the DataSource, the HibernateTransactionManager needs a reference to the SessionFactory.

txManager在这个例子中是HibernateTransactionManager类型的。相同的方式DataSourceTransactionManager需要一个数据源的引用,HibernateTransactionManager需要一个SessionFactory的引用。

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">

    <property name="dataSource" ref="dataSource"/>

    <property name="mappingResources">

        <list>

            <value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>

        </list>

    </property>

    <property name="hibernateProperties">

        <value>

            hibernate.dialect=${hibernate.dialect}

        </value>

    </property>

</bean>

<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">

    <property name="sessionFactory" ref="sessionFactory"/>

</bean>

If you are using Hibernate and Java EE container-managed JTA transactions, then you should simply use the same JtaTransactionManager as in the previous JTA example for JDBC.

如果你使用Hibernate和JavaEE容器管理JTA事务,你需要简单的使用相同的JtaTransactionManager在之前JTA例子中。

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>

[Note]

注意

If you use JTA , then your transaction manager definition will look the same regardless of what data access technology you use, be it JDBC, Hibernate JPA or any other supported technology. This is due to the fact that JTA transactions are global transactions, which can enlist any transactional resource.

如果你使用JTA,你的事务管理定义将查找相同而忽略数据访问的技术,可以是JDBC、Hibernate、JPA或其他技术。这取决于JTA事务是全局事务可以使用全部的事务资源。

In all these cases, application code does not need to change. You can change how transactions are managed merely by changing configuration, even if that change means moving from local to global transactions or vice versa.

在所有的这些例子中,应用代码不需要改变。你可以改变事务的管理通过改变配置即使改变意味着从本地到全局事务或反之亦然。

17.4 Synchronizing resources with transactions

事务中的资源同步

It should now be clear how you create different transaction managers, and how they are linked to related resources that need to be synchronized to transactions (for example DataSourceTransactionManager to a JDBC DataSource, HibernateTransactionManager to a Hibernate SessionFactory, and so forth). This section describes how the application code, directly or indirectly using a persistence API such as JDBC, Hibernate, or JDO, ensures that these resources are created, reused, and cleaned up properly. The section also discusses how transaction synchronization is triggered (optionally) through the relevant PlatformTransactionManager.

现在你应当清楚你是如何创建不同的事务管理并且他们关联到相关的资源需要同步对于事务来说(例如DataSourceTransactionManager用于JDBC数据源、HibernateTransactionManager用于Hibernate的SessionFactory等等。)这一节描述应用代码如何直接或间接的使用持久化API例如JDBC、HIbernate或JDO保证这些资源被创建、重用和清理在适当的时间。这一节也讨论事务的同步是如何引起的通过相关的PlatformTransactionManager。

17.4.1 High-level synchronization approach

高级的同步方法

The preferred approach is to use Spring’s highest level template based persistence integration APIs or to use native ORM APIs with transaction-aware factory beans or proxies for managing the native resource factories. These transaction-aware solutions internally handle resource creation and reuse, cleanup, optional transaction synchronization of the resources, and exception mapping. Thus user data access code does not have to address these tasks, but can be focused purely on non-boilerplate persistence logic. Generally, you use the native ORM API or take a template approach for JDBC access by using the JdbcTemplate. These solutions are detailed in subsequent chapters of this reference documentation.

较好的方式使用spring的高级别模板基于持久化API或使用本地的ORM的API来配合已知事务的工厂bean或用于管理本地资源工程的代理。这些已知事务的解决方案内部处理资源创建和重用、清理、选择事务资源同步和异常匹配。用户的数据访问代码不需要记录这些任务,但是可以强制使用持久化逻辑。通常,你使用本地的ORM的API或使用模板方法用于JDBC访问通过使用JdbcTemplate。这些解决方案在后续章节中介绍。

17.4.2 Low-level synchronization approach

低级的同步方法

Classes such as DataSourceUtils (for JDBC), EntityManagerFactoryUtils (for JPA), SessionFactoryUtils (for Hibernate), PersistenceManagerFactoryUtils (for JDO), and so on exist at a lower level. When you want the application code to deal directly with the resource types of the native persistence APIs, you use these classes to ensure that proper Spring Framework-managed instances are obtained, transactions are (optionally) synchronized, and exceptions that occur in the process are properly mapped to a consistent API.

DataSourceUtils(用于JDBC)、EntityManagerFactoryUtils(用于JPA)、SessionFactoryUtils(用于Hibernate),PersistenceManagerFactoryUtils(用于JDO)等等是低级别的类。当你希望应用代码来直接处理本地持久化API的资源类型,你使用这些类来保证适当的spring框架管理实例,事务是同步、异常发生和适当的匹配一致的API。

For example, in the case of JDBC, instead of the traditional JDBC approach of calling the getConnection() method on the DataSource, you instead use Spring’s org.springframework.jdbc.datasource.DataSourceUtils class as follows:

例如,在JDBC的案例中,代替传统的JDBC方法调用DataSource的getConnection方法,你使用spring的org.springframework.jdbc.datasource.DataSourceUtils类如下:

Connection conn = DataSourceUtils.getConnection(dataSource);

If an existing transaction already has a connection synchronized (linked) to it, that instance is returned. Otherwise, the method call triggers the creation of a new connection, which is (optionally) synchronized to any existing transaction, and made available for subsequent reuse in that same transaction. As mentioned, any SQLException is wrapped in a Spring Framework CannotGetJdbcConnectionException, one of the Spring Framework’s hierarchy of unchecked DataAccessExceptions. This approach gives you more information than can be obtained easily from the SQLException, and ensures portability across databases, even across different persistence technologies.

如果一个已经存在的事务已经有一个同步连接对于数据源,这个实例会返回。此外,这个方法调用创建新连接的触发器,(可选)同步对于任何已经存在的事务,并且对于相同事务中的后续请求有效。提到的,任何SQLException被spring框架的CannotGetJdbcConnectionException包裹,spring框架非捕获的DataAccessExceptions之一。这个方式给你更多的信息可以更好的获取从SQLException中,并且保证方便的跨数据库特性,即使跨越不通过的持久化技术。

This approach also works without Spring transaction management (transaction synchronization is optional), so you can use it whether or not you are using Spring for transaction management.

这个方法也可以脱离spring的事务管理(事务同步是可选的),因此你可以使用或放弃spring的事务管理。

Of course, once you have used Spring’s JDBC support, JPA support or Hibernate support, you will generally prefer not to use DataSourceUtils or the other helper classes, because you will be much happier working through the Spring abstraction than directly with the relevant APIs. For example, if you use the Spring JdbcTemplate or jdbc.object package to simplify your use of JDBC, correct connection retrieval occurs behind the scenes and you won’t need to write any special code.

当然,一旦你使用了spring的JDBC支持、JPA支持货Hibernate支持,你将不会使用DataSourceUtils或其他辅助类,因为你将更简单的使用spring的抽象根据相应的API。例如,你使用spring的JdbcTemplate或jdbc.object包来简单的使用JDBC,正确的连接检索发生在相关的场景之后并且你不需要书写特定的代码。

17.4.3 TransactionAwareDataSourceProxy

At the very lowest level exists the TransactionAwareDataSourceProxy class. This is a proxy for a target DataSource, which wraps the target DataSource to add awareness of Spring-managed transactions. In this respect, it is similar to a transactional JNDI DataSource as provided by a Java EE server.

在最低级存在的TransactionAwareDataSourceProxy类。这是一个代理对于目标的数据源,包裹目标数据源来添加spring管理的事务。在这方面,和JavaEE服务器提供的传统的JNDI数据源相似。

It should almost never be necessary or desirable to use this class, except when existing code must be called and passed a standard JDBC DataSource interface implementation. In that case, it is possible that this code is usable, but participating in Spring managed transactions. It is preferable to write your new code by using the higher level abstractions mentioned above.

这是不必要的或使用这些类是令人满意的,已有的代码被调用和传递标准的JDBC数据源接口实现。在这种情况下,这些代码是有用的,但是参与到spring的事务管理中。可以书写你的新代码通过使用上面提到的更高级的抽象。

17.5 Declarative transaction management

声明式事务管理

[Note]

注意

Most Spring Framework users choose declarative transaction management. This option has the least impact on application code, and hence is most consistent with the ideals of a non-invasive lightweight container.

大部分spring框架用户选择声明式事务管理。这个选项可以最少的侵入应用代码,并且符合一致性对于非侵入的轻量级容器。

The Spring Framework’s declarative transaction management is made possible with Spring aspect-oriented programming (AOP), although, as the transactional aspects code comes with the Spring Framework distribution and may be used in a boilerplate fashion, AOP concepts do not generally have to be understood to make effective use of this code.

spring框架的声明式事务管理使得spring的切面编程可行,尽管,事务方面的代码来自spring框架并且可以使用一种引用的形式,AOP内容不需要利用这些代码。

The Spring Framework’s declarative transaction management is similar to EJB CMT in that you can specify transaction behavior (or lack of it) down to individual method level. It is possible to make a setRollbackOnly() call within a transaction context if necessary. The differences between the two types of transaction management are:

spring框架的声明式事务管理和EJB CMT相似你可以定义特定的行为(或不定义)对于独立的方法模型。可以调用setRollbackOnly方法在事务上下文中如果有需要的化。这两种事务管理的不同是:

    Unlike EJB CMT, which is tied to JTA, the Spring Framework’s declarative transaction management works in any environment. It can work with JTA transactions or local transactions using JDBC, JPA, Hibernate or JDO by simply adjusting the configuration files.

不像EJB CMT可以绑定JTA,spring框架的声明式事务管理可以在任何环境使用。他可以使用JTA的事务或JDBC的本地事务、Hibernate或JDO通过修改配置文件。

    You can apply the Spring Framework declarative transaction management to any class, not merely special classes such as EJBs.

你可以应用spring框架声明事务管理对于任何类,并不特定指EJB的类。

    The Spring Framework offers declarative rollback rules,a feature with no EJB equivalent. Both programmatic and declarative support for rollback rules is provided.

spring框架提供了声明式的回滚原则,一个没有EJB的的特性。编程式和声明式对于回滚都支持。

    The Spring Framework enables you to customize transactional behavior, by using AOP. For example, you can insert custom behavior in the case of transaction rollback. You can also add arbitrary advice, along with the transactional advice. With EJB CMT, you cannot influence the container’s transaction management except with setRollbackOnly().

spring框架允许你通过AOP自定义一个事务行为。例如,你可以加入自定义行为用在事务的回滚中。你也可以添加任意的advice,和事务的advice在一起使用。使用EJB的CMT,你不能影响容器的事务管理除非setRollbackOnly方法。

    The Spring Framework does not support propagation of transaction contexts across remote calls, as do high-end application servers. If you need this feature, we recommend that you use EJB. However, consider carefully before using such a feature, because normally, one does not want transactions to span remote calls.

spring框架不支持事务的传播跨越远程调用,作为高端的应用服务器。如果你需要这个特性,我们将会建议你使用EJB。然而使用一个特性前请仔细考虑,因为正常情况下,不需要在分离的远程调用中使用事务。

Where is TransactionProxyFactoryBean?

那么TransactionProxyFactoryBean在哪里呢?

Declarative transaction configuration in versions of Spring 2.0 and above differs considerably from previous versions of Spring. The main difference is that there is no longer any need to configure TransactionProxyFactoryBean beans.

声明式事务管理配置在spring的2.0版本及以上,和之前的版本设置有所不同。主要的区别是不需要配置TransactionProxyFactoryBean的bean。

The pre-Spring 2.0 configuration style is still 100% valid configuration; think of the new <tx:tags/> as simply defining TransactionProxyFactoryBean beans on your behalf.

之前的spring2.0配置风格依然需要配置;考虑新的<tx:tags/>作为简单的定义TransactionProxyFactoryBean的bean在你的行为中。

The concept of rollback rules is important: they enable you to specify which exceptions (and throwables) should cause automatic rollback. You specify this declaratively, in configuration, not in Java code. So, although you can still call setRollbackOnly() on the TransactionStatus object to roll back the current transaction back, most often you can specify a rule that MyApplicationException must always result in rollback. The significant advantage to this option is that business objects do not depend on the transaction infrastructure. For example, they typically do not need to import Spring transaction APIs or other Spring APIs.

回滚规则的内容是重要的,他们允许你定义什么异常抛出后应当自动回滚。你只需要声明这些在配置中而不是你的代码中。因此,尽管你可以调用setRollbackOnly在TransactionStatus的object上来回滚当前的事务,大部分情况你可以定义一个规则就是MyApplicationException必须导致回滚。这个优点是业务object不需要依赖事务结构。例如,他们通常不需要导入spring的事务API或其他spring的API。

Although EJB container default behavior automatically rolls back the transaction on a system exception (usually a runtime exception), EJB CMT does not roll back the transaction automatically on anapplication exception (that is, a checked exception other than java.rmi.RemoteException). While the Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions), it is often useful to customize this behavior.

尽管EJB容器默认的行为自动回滚事务由于一个系统异常(使用一个运行时异常),EJB的CMT不需要自动回滚事务对于应用异常(就是,检查异常除了java.rmi.RemoteException)。当spring的默认行为对于声明式事务管理符合EJB的规范(回滚是自动的仅当出现非检查异常)这对于自定义行为有好处。

17.5.1 Understanding the Spring Framework’s declarative transaction implementation

理解spring框架的声明式事务实现

It is not sufficient to tell you simply to annotate your classes with the @Transactional annotation, add @EnableTransactionManagement to your configuration, and then expect you to understand how it all works. This section explains the inner workings of the Spring Framework’s declarative transaction infrastructure in the event of transaction-related issues.

仅仅告诉你简单直接你的类通过使用@Transactional注解是不充足,添加@EnableTransactionManagement到你的配置中,除非你了解她们是怎么样工作的。这一节解释spring框架声明式事务的架构的内部构造在一个事务相关的问题中。

The most important concepts to grasp with regard to the Spring Framework’s declarative transaction support are that this support is enabled via AOP proxies, and that the transactional advice is driven by metadata (currently XML- or annotation-based). The combination of AOP with transactional metadata yields an AOP proxy that uses a TransactionInterceptor in conjunction with an appropriate PlatformTransactionManager implementation to drive transactions around method invocations.

最重要的内容关于spring框架的声明式事务支持就是这个支持允许AOP代理,并且事务advice是基于元数据的(当然是XML或基于注解的)。AOP传统元数据和AOP的组合投入到AOP代理使用了TransactionInterceptor配合适当的PlatformTransactionManager实现来控制事务在方法调用中。

[Note]

注意

Spring AOP is covered in Chapter 11, Aspect Oriented Programming with Spring.

spring的AOP在章节11中已经介绍了,使用spring的面向切面的编程。

Conceptually, calling a method on a transactional proxy looks like this…​

概念上,调用一个事务方法代理看上去就像。

【Spring】Spring Framework Reference Documentation中文版13

17.5.2 Example of declarative transaction implementation

声明式事务实现的例子

Consider the following interface, and its attendant implementation. This example uses Foo and Bar classes as placeholders so that you can concentrate on the transaction usage without focusing on a particular domain model. For the purposes of this example, the fact that the DefaultFooService class throws UnsupportedOperationException instances in the body of each implemented method is good; it allows you to see transactions created and then rolled back in response to the UnsupportedOperationException instance.

考虑下面的接口并且他的额外实现。这个例子使用了Foo和Bar类作为占位符因此你可以关注于事务的使用而不是关注于特定的领域模型。这个例子的目的是,实际DefaultFooService类抛出了UnsupportedOperationException实例在每个实现的方法是好的,他允许你看到实物创建和回滚由于UnsupportedOperationException实例。

// the service interface that we want to make transactional

// 我们希望使用事务的服务

package x.y.service;

public interface FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);

}

// an implementation of the above interface

// 一个实现对于上面的接口

package x.y.service;

public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {

        throw new UnsupportedOperationException();

    }

    public Foo getFoo(String fooName, String barName) {

        throw new UnsupportedOperationException();

    }

    public void insertFoo(Foo foo) {

        throw new UnsupportedOperationException();

    }

    public void updateFoo(Foo foo) {

        throw new UnsupportedOperationException();

    }

}

Assume that the first two methods of the FooService interface, getFoo(String) and getFoo(String, String), must execute in the context of a transaction with read-only semantics, and that the other methods, insertFoo(Foo) and updateFoo(Foo), must execute in the context of a transaction with read-write semantics. The following configuration is explained in detail in the next few paragraphs.

假设前两个方法对于FooService接口,getFoo(String)和getFoo(String, String)必须执行在事务的上下文中和一个只读的语义,并且其他方法insertFoo(Foo)和pdateFoo(Foo)必须执行在事务的上下文和读写的语义。下面的配置解释在下面的部分中。

<!-- from the file 'context.xml' -->

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- this is the service object that we want to make transactional -->

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) -->

    <tx:advice id="txAdvice" transaction-manager="txManager">

        <!-- the transactional semantics... -->

        <tx:attributes>

            <!-- all methods starting with 'get' are read-only -->

            <tx:method name="get*" read-only="true"/>

            <!-- other methods use the default transaction settings (see below) -->

            <tx:method name="*"/>

        </tx:attributes>

    </tx:advice>

    <!-- ensure that the above transactional advice runs for any execution

        of an operation defined by the FooService interface -->

    <aop:config>

        <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>

    </aop:config>

    <!-- don't forget the DataSource -->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>

        <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>

        <property name="username" value="scott"/>

        <property name="password" value="tiger"/>

    </bean>

    <!-- similarly, don't forget the PlatformTransactionManager -->

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource"/>

    </bean>

    <!-- other <bean/> definitions here -->

</beans>

Examine the preceding configuration. You want to make a service object, the fooService bean, transactional. The transaction semantics to apply are encapsulated in the <tx:advice/> definition. The <tx:advice/> definition reads as "…​ all methods on starting with 'get' are to execute in the context of a read-only transaction, and all other methods are to execute with the default transaction semantics". The transaction-manager attribute of the <tx:advice/> tag is set to the name of the PlatformTransactionManager bean that is going to drive the transactions, in this case, the txManager bean.

检查之前的配置。你希望使用一个服务object,fooService的bean。事务语义对于应用是封闭的在<tx:advice/>定义中。<tx:advice/>定义读作“...所有方法开始与get被执行在一个只读事务的上下文中,并且所有其他方法被执行使用默认的事务语义”。<tx:advice/>标签中的transaction-manager属性被设置为PlatformTransactionManager的bean的名字将会处理事务在这个例子中,就是txManager的bean。

[Tip]

提示

You can omit the transaction-manager attribute in the transactional advice ( <tx:advice/>) if the bean name of the PlatformTransactionManager that you want to wire in has the name transactionManager. If the PlatformTransactionManager bean that you want to wire in has any other name, then you must use the transaction-manager attribute explicitly, as in the preceding example.

你可以省略transaction-manager在事务的advice( <tx:advice/>)如果PlatformTransactionManager的bean的名字你希望是transactionManager。如果PlatformTransactionManager的bean你希望连接他有其他的名字,你必须明确的使用transaction-manager就像之前的例子中一样。

The <aop:config/> definition ensures that the transactional advice defined by the txAdvice bean executes at the appropriate points in the program. First you define a pointcut that matches the execution of any operation defined in the FooService interface ( fooServiceOperation). Then you associate the pointcut with the txAdvice using an advisor. The result indicates that at the execution of a fooServiceOperation, the advice defined by txAdvice will be run.

<aop:config/>定义保证事务的advice定义通过txAdvice的bean执行在程序中的适当的位置。首先你定义一个切点匹配任何操作的执行定义在FooService接口(fooServiceOperation)。你连接切点和txAdvice使用一个advisor。结果就是在fooServiceOperation的执行中,通过txAdvice定义的advice将被运行。

The expression defined within the <aop:pointcut/> element is an AspectJ pointcut expression; see Chapter 11, Aspect Oriented Programming with Spring for more details on pointcut expressions in Spring.

使用<aop:pointcut/>元素定义的表达式是一个AspectJ切点表达式;见章节11,spring面向切面的编程来查看更多有关spring切点的信息。

A common requirement is to make an entire service layer transactional. The best way to do this is simply to change the pointcut expression to match any operation in your service layer. For example:

一个通用的请求来使得全局的服务事务层。最好的方法就是简单的改变切点表达式来匹配每个操作在你的服务层。例如:

<aop:config>

    <aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>

    <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>

</aop:config>

[Note]

注意

In this example it is assumed that all your service interfaces are defined in the x.y.service package; see Chapter 11, Aspect Oriented Programming with Spring for more details.

在这个例子中,他假设你所有的服务接口被定义在x.y.service的包中;见章节11,spring面向切面的编程来了解更多。

Now that we’ve analyzed the configuration, you may be asking yourself, "Okay…​ but what does all this configuration actually do?".

现在我们分析这个配置,你可以问一下自己“ok。。。但是这些配置实际是做什么的?”

The above configuration will be used to create a transactional proxy around the object that is created from the fooService bean definition. The proxy will be configured with the transactional advice, so that when an appropriate method is invoked on the proxy, a transaction is started, suspended, marked as read-only, and so on, depending on the transaction configuration associated with that method. Consider the following program that test drives the above configuration:

上面的配置将被用于创建一个事务代理来包裹object创建自fooService的bean定义。代理将被配置使用事务的advice,因此一个适当的方法被调用在代理中,一个事务的开始、挂起、标识为只读等等,依赖于是我配置关联的方法。考虑下面的程序来测试上面的配置:

public final class Boot {

    public static void main(final String[] args) throws Exception {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);

        FooService fooService = (FooService) ctx.getBean("fooService");

        fooService.insertFoo (new Foo());

    }

}

The output from running the preceding program will resemble the following. (The Log4J output and the stack trace from the UnsupportedOperationException thrown by the insertFoo(..) method of the DefaultFooService class have been truncated for clarity.)

输出来自运行之前的程序将类似如下。(Log4J输出和栈追踪来自insertFoo方法抛出的UnsupportedOperationException将会更加清楚)。

<!-- the Spring container is starting up... -->

[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy for bean 'fooService' with 0 common interceptors and 1 specific interceptors

<!-- the DefaultFooService is actually proxied -->

[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]

<!-- ... the insertFoo(..) method is now being invoked on the proxy -->

[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo

<!-- the transactional advice kicks in here... -->

[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]

[DataSourceTransactionManager] - Acquired Connection [[email protected]] for JDBC transaction

<!-- the insertFoo(..) method from DefaultFooService throws an exception... -->

[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should rollback on java.lang.UnsupportedOperationException

[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo due to throwable [java.lang.UnsupportedOperationException]

<!-- and the transaction is rolled back (by default, RuntimeException instances cause rollback) -->

[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [[email protected]]

[DataSourceTransactionManager] - Releasing JDBC Connection after transaction

[DataSourceUtils] - Returning JDBC Connection to DataSource

Exception in thread "main" java.lang.UnsupportedOperationException at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)

<!-- AOP infrastructure stack trace elements removed for clarity -->

at $Proxy0.insertFoo(Unknown Source)

at Boot.main(Boot.java:11)

17.5.3 Rolling back a declarative transaction

回滚一个声明式事务

The previous section outlined the basics of how to specify transactional settings for classes, typically service layer classes, declaratively in your application. This section describes how you can control the rollback of transactions in a simple declarative fashion.

之前的章节概述了基本的如何定义事务设置为某些类,特别是服务层的类,定义在你的应用中。这一节介绍你如何控制事务的回滚在一个简单的声明式的风格中。

The recommended way to indicate to the Spring Framework’s transaction infrastructure that a transaction’s work is to be rolled back is to throw an Exception from code that is currently executing in the context of a transaction. The Spring Framework’s transaction infrastructure code will catch any unhandled Exception as it bubbles up the call stack, and make a determination whether to mark the transaction for rollback.

建议的方式是声明对于spring框架的事务基础结构就是一个事务是否可以回滚来抛出一个异常来自代码执行在事务的上下文中。spring框架的事务基础代码将捕获任何未捕获的异常来到调用栈,并且做决定是否让事务回滚。

In its default configuration, the Spring Framework’s transaction infrastructure code only marks a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. ( Errors will also - by default - result in a rollback). Checked exceptions that are thrown from a transactional method do not result in rollback in the default configuration.

在他的默认配置中,spring框架的事务基础代码只能标记一个事务为回滚由于运行时非检查异常;就是,当抛出异常时一个RuntimeException的子类实例。(Errors也是可以的————默认情况下————导致回滚)。检查异常被事务方法扔出并不会导致回滚在默认配置下。

You can configure exactly which Exception types mark a transaction for rollback, including checked exceptions. The following XML snippet demonstrates how you configure rollback for a checked, application-specific Exception type.

你可以配置某个异常类型标记一个事务为回滚,包括检查异常。下面的xml片段展示了如何配置一个应用自定义异常类型。

<tx:advice id="txAdvice" transaction-manager="txManager">

    <tx:attributes>

    <tx:method name="get*" read-only="true" rollback-for="NoProductInStockException"/>

    <tx:method name="*"/>

    </tx:attributes>

</tx:advice>

You can also specify 'no rollback rules', if you do not want a transaction rolled back when an exception is thrown. The following example tells the Spring Framework’s transaction infrastructure to commit the attendant transaction even in the face of an unhandled InstrumentNotFoundException.

你也可以指定“不回滚的规则”,如果你不希望事务回滚由于某个异常。下面的例子将告诉spring框架事务的基础框架来提交事务即使出现了非处理的InstrumentNotFoundException异常。

<tx:advice id="txAdvice">

    <tx:attributes>

    <tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>

    <tx:method name="*"/>

    </tx:attributes>

</tx:advice>

When the Spring Framework’s transaction infrastructure catches an exception and is consults configured rollback rules to determine whether to mark the transaction for rollback, the strongest matching rule wins. So in the case of the following configuration, any exception other than an InstrumentNotFoundException results in a rollback of the attendant transaction.

当spring框架事务基础捕获一个异常并且查询回滚规则来决定是否标记事务为回滚时,最强的规则为准。因此由于下面的配置,任何异常除了InstrumentNotFoundException导致一个事务会回滚。

<tx:advice id="txAdvice">

    <tx:attributes>

    <tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>

    </tx:attributes>

</tx:advice>

You can also indicate a required rollback programmatically. Although very simple, this process is quite invasive, and tightly couples your code to the Spring Framework’s transaction infrastructure:

你也可以指定一个需要的回滚。尽管特别简单,这依然是具有侵入性的,并且将你的代码和spring的事务基础绑定在一起。

public void resolvePosition() {

    try {

        // some business logic...

    } catch (NoProductInStockException ex) {

        // trigger rollback programmatically

        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

    }

}

You are strongly encouraged to use the declarative approach to rollback if at all possible. Programmatic rollback is available should you absolutely need it, but its usage flies in the face of achieving a clean POJO-based architecture.

强烈建议你使用声明式的方式如果可行的话。编程式的回滚只有在你特别需要的时候使用,但是他的使用文件获得一个干净的基于POJO的基础。

17.5.4 Configuring different transactional semantics for different beans

配置不同的事务语义对于不同的bean

Consider the scenario where you have a number of service layer objects, and you want to apply a totally different transactional configuration to each of them. You do this by defining distinct <aop:advisor/> elements with differing pointcut and advice-ref attribute values.

考虑一个场景当你有一些服务层的object,并且你希望应用一个不同的配置对于每一个object。你对于每个切点定义<aop:advisor/>元素和advice-ref属性值。

As a point of comparison, first assume that all of your service layer classes are defined in a root x.y.service package. To make all beans that are instances of classes defined in that package (or in subpackages) and that have names ending in Service have the default transactional configuration, you would write the following:

作为一个点的比较,首先假设你所有服务层的类被定义到一个x.y.service包中。为了保证所有的bean是类的实例定义在包中(或子包中)并且对于名字有默认的事务配置,你可以这样写:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:config>

        <aop:pointcut id="serviceOperation"

                expression="execution(* x.y.service..*Service.*(..))"/>

        <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>

    </aop:config>

    <!-- these two beans will be transactional... -->

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <bean id="barService" class="x.y.service.extras.SimpleBarService"/>

    <!-- ... and these two beans won't -->

    <bean id="anotherService" class="org.xyz.SomeService"/> <!-- (not in the right package) -->

    <bean id="barManager" class="x.y.service.SimpleBarManager"/> <!-- (doesn't end in 'Service') -->

    <tx:advice id="txAdvice">

        <tx:attributes>

            <tx:method name="get*" read-only="true"/>

            <tx:method name="*"/>

        </tx:attributes>

    </tx:advice>

    <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->

</beans>

The following example shows how to configure two distinct beans with totally different transactional settings.

下面的例子展示了如何配置两个不同的bean有不同的事务配置。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:config>

        <aop:pointcut id="defaultServiceOperation"

                expression="execution(* x.y.service.*Service.*(..))"/>

        <aop:pointcut id="noTxServiceOperation"

                expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>

        <aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>

        <aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>

    </aop:config>

    <!-- this bean will be transactional (see the 'defaultServiceOperation' pointcut) -->

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- this bean will also be transactional, but with totally different transactional settings -->

    <bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>

    <tx:advice id="defaultTxAdvice">

        <tx:attributes>

            <tx:method name="get*" read-only="true"/>

            <tx:method name="*"/>

        </tx:attributes>

    </tx:advice>

    <tx:advice id="noTxAdvice">

        <tx:attributes>

            <tx:method name="*" propagation="NEVER"/>

        </tx:attributes>

    </tx:advice>

    <!-- other transaction infrastructure beans such as a PlatformTransactionManager omitted... -->

</beans>

17.5.5 <tx:advice/> settings

<tx:advice/>设置

This section summarizes the various transactional settings that can be specified using the <tx:advice/> tag. The default <tx:advice/> settings are:

这一节总结了不同事务设置对于使用<tx:advice/>标签。默认的<tx:advice/>设置是:

    Propagation setting is REQUIRED.

传播设置是REQUIRED

    Isolation level is DEFAULT.

隔离级别是DEFAULT

    Transaction is read/write.

事务是读写的

    Transaction timeout defaults to the default timeout of the underlying transaction system, or none if timeouts are not supported.

事务超时默认是取决于底层的事务系统或不支持超时。

    Any RuntimeException triggers rollback, and any checked Exception does not.

任何运行时异常会导致回滚并且任何检查异常不会。

You can change these default settings; the various attributes of the <tx:method/> tags that are nested within <tx:advice/> and <tx:attributes/> tags are summarized below:

你可以改变默认的设置,需要使用嵌入到<tx:advice/>中的<tx:method/>标签并且总结如下:

Table 17.1. <tx:method/> settings

<tx:method/>设置

Attribute

属性

Required?

是否必须

Default

默认

Description

描述

name

名字

Yes

必须

Method name(s) with which the transaction attributes are to be associated. The wildcard (*) character can be used to associate the same transaction attribute settings with a number of methods; for example, get*, handle*, on*Event, and so forth.

方法名对于事务属性是关联的。通配符可以使用关联相同的事务属性设置一些方法,例如,get*、handle*、on*Event等等

propagation

传播

No

非必须

REQUIRED

Transaction propagation behavior.

事务的传播行为

isolation

隔离

No

非必须

DEFAULT

Transaction isolation level.

事务的隔离级别

timeout

超时

No

非必须

-1

Transaction timeout value (in seconds).

事务超时值,单位是秒

read-only

只读

No

非必须

FALSE

Is this transaction read-only?

事务是否是只读的

rollback-for

用于回滚

No

非必须

Exception(s) that trigger rollback; comma-delimited. For example, com.foo.MyBusinessException,ServletException.

对于异常回滚事务例如,com.foo.MyBusinessException,ServletException

no-rollback-for

不用回滚

No

非必须

Exception(s) that do not trigger rollback; comma-delimited. For example, com.foo.MyBusinessException,ServletException.

对于异常不回滚事务例如,com.foo.MyBusinessException,ServletException

17.5.6 Using @Transactional

使用@Transactional

In addition to the XML-based declarative approach to transaction configuration, you can use an annotation-based approach. Declaring transaction semantics directly in the Java source code puts the declarations much closer to the affected code. There is not much danger of undue coupling, because code that is meant to be used transactionally is almost always deployed that way anyway.

额外的对于基于xml的声明式方法对于事务的配置,你可以使用一个基于注解的方式。声明式的事务语义直接在java源码中加入了声明更加靠近代码。过度这么使用不会有危险,因为代码意味着使用事务大部分是任意部署的。

[Note]

注意

The standard javax.transaction.Transactional annotation is also supported as a drop-in replacement to Spring’s own annotation. Please refer to JTA 1.2 documentation for more details.

标准的javax.transaction.Transactional注解也支持插入到spring自己的注解中。请参考JTA1.2文档来了解更多细节。

The ease-of-use afforded by the use of the @Transactional annotation is best illustrated with an example, which is explained in the text that follows. Consider the following class definition:

方便使用提供了使用@Transactional注解是最好的展示方式对于案例,将在文本中解释如下。考虑下面的类定义:

// the service class that we want to make transactional

// 我们希望将服务类加上事务

@Transactional

public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);

}

When the above POJO is defined as a bean in a Spring IoC container, the bean instance can be made transactional by adding merely one line of XML configuration:

当上面的POJO被定义作为一个bean在spring的IOC容器中,bean实例可以事务化通过添加一行xml配置:

<!-- from the file 'context.xml' -->

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- this is the service object that we want to make transactional -->

<!-- 一个服务object我们希望事务化 -->

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- enable the configuration of transactional behavior based on annotations -->

<!-- 允许事务的配置行为基于注解 -->

    <tx:annotation-driven transaction-manager="txManager"/><!-- a PlatformTransactionManager is still required -->

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <!-- (this dependency is defined somewhere else) -->

        <property name="dataSource" ref="dataSource"/>

    </bean>

    <!-- other <bean/> definitions here -->

</beans>

[Tip]

提示

You can omit the transaction-manager attribute in the <tx:annotation-driven/> tag if the bean name of the PlatformTransactionManager that you want to wire in has the name transactionManager. If the PlatformTransactionManager bean that you want to dependency-inject has any other name, then you have to use the transaction-manager attribute explicitly, as in the preceding example.

你可以省略<tx:annotation-driven/>标签中的transaction-manager属性,如果PlatformTransactionManager的bean的名字你希望是transactionManager。如果PlatformTransactionManager的bean你希望依赖注意另一个名字,你必须明确的使用transaction-manager属性在前面的例子中。

[Note]

注意

The @EnableTransactionManagement annotation provides equivalent support if you are using Java based configuration. Simply add the annotation to a @Configuration class. See the javadocs for full details.

@EnableTransactionManagement注解提供了相同的支持如果你使用基于Java的配置。简单的添加注解对于@Configuration类。见相关的javadocs来了解细节。

Method visibility and @Transactional

方法可见和@Transactional

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

当你使用代理,你应当应用@Transactional注解只有方法是public可见的。如果修饰符是protected、private或包可见的方法使用@Transactional注解,不会出现任何错误但是注解方法不会出现事务的设置。考虑使用AspectJ(见下面)如果你修饰一个非public方法。

You can place the @Transactional annotation before an interface definition, a method on an interface, a class definition, or a public method on a class. However, the mere presence of the @Transactional annotation is not enough to activate the transactional behavior. The @Transactional annotation is simply metadata that can be consumed by some runtime infrastructure that is @Transactional-aware and that can use the metadata to configure the appropriate beans with transactional behavior. In the preceding example, the <tx:annotation-driven/> element switches on the transactional behavior.

你可以替代@Transactional注解在一个接口定义、一个方法在一个接口、一个类定义或一个类的公共方法。然而,@Transactional是不够的对于激活事务行为。@Transactional注解只是简单元数据可以被使用通过一个运行环境是@Transactional-aware的并且可以使用元数据来配置适当的bean使用事务行为。在前面的例子中,<tx:annotation-driven/>元素打开了事务的行为。

[Tip]

提示

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-target-class="true") or the weaving-based aspect ( mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.

spring建议你注解相关的类(和相关类的方法)使用@Transactional注解,作为注解接口的对照。你可以替代@Transactional注解在一个接口(或一个接口方法),但是只有当你使用基于接口的代理才会发挥作用。事实就是Java注解不会继承自接口如果你使用基于类的代理(proxy-target-class="true")或基于包裹的方面(mode="aspectj"),然后事务设置不会被代理意识到和包裹基础组件和object将不会被代理处理如果是bad的。

[Note]

注意

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.

在代理模式(默认情况下),只有外部方法调用通过代理被拦截。这个方式是自调用的,实际上,一个方法使用目标object调用其他方法对于目标object,将不会导致实际的事务在运行时即使调用方法标记了@Transactional。并且代理必须完全初始化来提供期望的行为因此你应当依赖他在初始化代码的特性,也就是说@PostConstruct。

Consider the use of AspectJ mode (see mode attribute in table below) if you expect self-invocations to be wrapped with transactions as well. In this case, there will not be a proxy in the first place; instead, the target class will be weaved (that is, its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

考虑使用AspectJ模型(见下面表中的属性)如果你期望自调用来处理事务。在这种情况下,他将不会被代理在首先的位置,作为代替,目标类将被处理(也就是他的二进制代码被更改)用于改变@Transactional到运行时行为对于任何类型的方法。

Table 17.2. Annotation driven transaction settings

基于注解的事务设置

XML Attribute

xml属性

Annotation Attribute

注解属性

Default

默认值

Description

描述

transaction-manager N/A (See TransactionManagementConfigurer javadocs) transactionManager

Name of transaction manager to use. Only required if the name of the transaction manager is not transactionManager, as in the example above.

使用的事务管理的名字。如果名字不是transactionManager的时候才需要指定,见上面的例子。

mode mode proxy

The default mode "proxy" processes annotated beans to be proxied using Spring’s AOP framework (following proxy semantics, as discussed above, applying to method calls coming in through the proxy only). The alternative mode "aspectj" instead weaves the affected classes with Spring’s AspectJ transaction aspect, modifying the target class byte code to apply to any kind of method call. AspectJ weaving requires spring-aspects.jar in the classpath as well as load-time weaving (or compile-time weaving) enabled. (See the section called “Spring configuration” for details on how to set up load-time weaving.)

默认的模式代理执行注解bean来注解使用spring的aop框架(符合代理语义,讨论如上,应用方法调用只会通过代理)。另一个模式是aspectj处理影响的类使用spring的AspectJ事务方面修改目标二进制代码来应用不同方法的调用。AspectJ处理需要spring-aspects.jar在classpath中并且在加载时处理(或编译时处理)也可以。(见章节“spring的配置”来了解设置加载时处理的细节。)

proxy-target-class proxyTargetClass FALSE

Applies to proxy mode only. Controls what type of transactional proxies are created for classes annotated with the @Transactional annotation. If the proxy-target-class attribute is set to true, then class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, then standard JDK interface-based proxies are created. (See Section 11.6, “Proxying mechanisms” for a detailed examination of the different proxy types.)

只应用代理模式。控制事务代理的类型是创建自类使用了@Transactional注解。如果代理目标类的属性被设置为true,那么基于类的代理被创建。如果代理目标类是false或如果属性是省略的,则标准的JDK基于接口的代理被创建。(见11.6章节“代理策略”来了解不同代理类型的区别。)

order order Ordered.LOWEST_PRECEDENCE

Defines the order of the transaction advice that is applied to beans annotated with @Transactional. (For more information about the rules related to ordering of AOP advice, see the section called “Advice ordering”.) No specified ordering means that the AOP subsystem determines the order of the advice.

定义事务advice的顺序可以应用于bean使用了@Transactional注解。(更多信息关于AOP的advice的顺序见章节“Adivce的顺序”。)不需要指定方式AOP的子系统决定advice的顺序。

[Note]

注意

The proxy-target-class attribute controls what type of transactional proxies are created for classes annotated with the @Transactional annotation. If proxy-target-class is set to true, class-based proxies are created. If proxy-target-class is false or if the attribute is omitted, standard JDK interface-based proxies are created. (See Section 11.6, “Proxying mechanisms” for a discussion of the different proxy types.)

proxy-target-class属性控制事务代理被创建的类型对于注解了@Transactional注解的类。如果proxy-target-class设置为true,基于类的代理被创建。如果proxy-target-class是false或者属性是省略的,标准的JDK的基于接口的代理被创建。(将11.6“代理策略”来了解详细的信息)

[Note]

注意

@EnableTransactionManagement and <tx:annotation-driven/> only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services. See Section 22.2, “The DispatcherServlet” for more information.

@EnableTransactionManagement和<tx:annotation-driven/>会查找标记了@Transactional的bean在一些相同的应用上下文中。这意味着,如果你将注解放入配置为了DispatcherServlet到WebApplicationContext中,他只会检查你控制器上的@Transactional的bean而不是你的服务。见章节22.2节,“DispatcherServlet”来了解更多信息。

The most derived location takes precedence when evaluating the transactional settings for a method. In the case of the following example, the DefaultFooService class is annotated at the class level with the settings for a read-only transaction, but the @Transactional annotation on the updateFoo(Foo) method in the same class takes precedence over the transactional settings defined at the class level.

大部分派生位置优先当评价事务设置对于一个方法。在下面的例子中,DefaultFooService类是声明在类级别使用了一个只读事务的设置,但是@Transactional注解在updateFoo方法在同一个类会优先在类的级别通过事务的设置。

@Transactional(readOnly = true)

public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {

        // do something

    }

    // these settings have precedence for this method

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)

    public void updateFoo(Foo foo) {

        // do something

    }

}

@Transactional settings

The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction". The default @Transactional settings are as follows:

@Transactional注解是元数据定义了一个接口、类或方法必须有事务语义,例如,“开启一个全新的只读事务当方法被调用,挂起任何已有的事务”。默认的@Transactional设置如下:

    Propagation setting is PROPAGATION_REQUIRED.

传播设置为PROPAGATION_REQUIRED

    Isolation level is ISOLATION_DEFAULT.

隔离级别是ISOLATION_DEFAULT

    Transaction is read/write.

事务是读写

    Transaction timeout defaults to the default timeout of the underlying transaction system, or to none if timeouts are not supported.

事务超时默认定义有下面的事务系统或不支持超时的定义。

    Any RuntimeException triggers rollback, and any checked Exception does not.

任何运行时异常会导致回滚,但任何非检查异常不会。

These default settings can be changed; the various properties of the @Transactional annotation are summarized in the following table:

这些默认的设置可以被改变,@Transactional注解的不同属性总结在下面的表中:

Table 17.3. @Transactional Settings

@Transactional设置

Property

属性

Type

类型

Description

描述

value String

Optional qualifier specifying the transaction manager to be used.

可选的限定指定使用的事务管理器

propagation enum: Propagation

Optional propagation setting.

可选的传播设置

isolation enum: Isolation

Optional isolation level.

可选的隔离级别

readOnly boolean

Read/write vs. read-only transaction

读写或只读事务

timeout int (in seconds granularity)

Transaction timeout.

事务超时

rollbackFor

Array of Class objects, which must be derived from Throwable.

Class数组object,必须派生自Throwable

Optional array of exception classes that must cause rollback.

可选的异常类数组用于发生后导致回滚

rollbackForClassName

Array of class names. Classes must be derived from Throwable.

类名数组。类必须派生自Throwable

Optional array of names of exception classes that must cause rollback.

可选的异常类名数组会导致回滚

noRollbackFor

Array of Class objects, which must be derived from Throwable.

Class数组object,必须派生自Throwable

Optional array of exception classes that must not cause rollback.

可选的异常类数组用于发生后不会导致回滚

noRollbackForClassName

Array of String class names, which must be derived from Throwable.

类名数组。类必须派生自Throwable

Optional array of names of exception classes that must not cause rollback.

可选的异常类名数组不会导致回滚

Currently you cannot have explicit control over the name of a transaction, where 'name' means the transaction name that will be shown in a transaction monitor, if applicable (for example, WebLogic’s transaction monitor), and in logging output. For declarative transactions, the transaction name is always the fully-qualified class name + "." + method name of the transactionally-advised class. For example, if the handlePayment(..) method of the BusinessService class started a transaction, the name of the transaction would be: com.foo.BusinessService.handlePayment.

当前你不能明确控制事务的名字,当name意味着事务的名字将被展示在事务监视器中,如果可以(例如,WebLogic事务监视器),和在日志输出。对于声明式事务,事务的名字是全限定名加上点加上事务类的方法名。例如,如果handlePayment方法是BusinessService类的并且开启一个事务,事务的名字将会是:com.foo.BusinessService.handlePayment。

Multiple Transaction Managers with @Transactional

多个事务管理通过@Transactional

Most Spring applications only need a single transaction manager, but there may be situations where you want multiple independent transaction managers in a single application. The value attribute of the @Transactional annotation can be used to optionally specify the identity of the PlatformTransactionManager to be used. This can either be the bean name or the qualifier value of the transaction manager bean. For example, using the qualifier notation, the following Java code

大部分spring的应用只需要一个单独的事务管理,但是有一种情况当你希望多个独立的事务管理在一个单独的应用中。@Transactional注解的value属性可以被使用来指定使用的PlatformTransactionManager。可以是bean的名字或事务管理器bean的全限定value。例如,使用全限定标识,如下面的Java代码。

public class TransactionalService {

    @Transactional("order")

    public void setSomething(String name) { ... }

    @Transactional("account")

    public void doSomething() { ... }

}

could be combined with the following transaction manager bean declarations in the application context.

可以配合下面的事务管理bean定义在应用上下文中。

<tx:annotation-driven/>

    <bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        ...

        <qualifier value="order"/>

    </bean>

    <bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        ...

        <qualifier value="account"/>

    </bean>

In this case, the two methods on TransactionalService will run under separate transaction managers, differentiated by the "order" and "account" qualifiers. The default <tx:annotation-driven> target bean name transactionManager will still be used if no specifically qualified PlatformTransactionManager bean is found.

在这个例子,TransactionalService的两个方法将运行在分开的事务管理器中,通过order和account来区分。默认的<tx:annotation-driven>目标bean的名字transactionManager将依然被使用如果没有特定的全限定PlatformTransactionManager的bean被找到。

Custom shortcut annotations

自定义简单的注解

If you find you are repeatedly using the same attributes with @Transactional on many different methods, then Spring’s meta-annotation support allows you to define custom shortcut annotations for your specific use cases. For example, defining the following annotations

如果你发现重复的使用相同的属性在@Transactional对于很多方法,spring的元注解支持允许你定义自定义的简单注解为你特定的使用案例。例如,定义一个如下的注解。

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Transactional("order")

public @interface OrderTx {

}

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Transactional("account")

public @interface AccountTx {

}

allows us to write the example from the previous section as

允许你书写之前的例子如下

public class TransactionalService {

    @OrderTx

    public void setSomething(String name) { ... }

    @AccountTx

    public void doSomething() { ... }

}

Here we have used the syntax to define the transaction manager qualifier, but could also have included propagation behavior, rollback rules, timeouts etc.

这里我们使用语法定义了事务管理器全限定,但是也包括的了传播行为、回滚行为、超时等等。

17.5.7 Transaction propagation

事务的传播

This section describes some semantics of transaction propagation in Spring. Please note that this section is not an introduction to transaction propagation proper; rather it details some of the semantics regarding transaction propagation in Spring.

这节描述了spring中一些事务传播的语义。请注意这一节不是介绍事务传播,而是他在spring中的语义。

In Spring-managed transactions, be aware of the difference between physical and logical transactions, and how the propagation setting applies to this difference.

在spring管理的事务,意识到物理和逻辑事务的不同,以及如何对于这些不同进行传播行为的设置。

Required

要求

【Spring】Spring Framework Reference Documentation中文版13

PROPAGATION_REQUIRED

When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. Each such logical transaction scope can determine rollback-only status individually, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction’s chance to actually commit (as you would expect it to).

当传播设置为PROPAGATION_REQUIRED,一个逻辑事务范围被创建对于不同的方法和应用的设置。每个这样的逻辑事务范围可以独立决定回滚的状态,是否一个外部事务范围是逻辑独立的对于内部的事务范围。当然,由于标准的PROPAGATION_REQUIRED行为,所有这些范围将对应于一些物理的事务。因此一个回滚的标记设置在内部事务范围影响了外部事务提交的机会(和你想的一样)

However, in the case where an inner transaction scope sets the rollback-only marker, the outer transaction has not decided on the rollback itself, and so the rollback (silently triggered by the inner transaction scope) is unexpected. A corresponding UnexpectedRollbackException is thrown at that point. This is expected behavior so that the caller of a transaction can never be misled to assume that a commit was performed when it really was not. So if an inner transaction (of which the outer caller is not aware) silently marks a transaction as rollback-only, the outer caller still calls commit. The outer caller needs to receive an UnexpectedRollbackException to indicate clearly that a rollback was performed instead.

然而,由于当一个内部事务方法设置为回滚标识,外部事务没有决定回滚并且回滚(由内部事务引发)是不可预见的。一个相应的UnexpectedRollbackException被抛出在那个时候。这是期望的行为因此事务的调用者不能假设他提交实际却没有提交。因此如果一个内部事务(外部调用者没有察觉)标记一个事务为回滚,外部调用者依然会调用提交。外部调用者需要收到一个UnexpectedRollbackException来明确指定一个回滚被替代了。

RequiresNew

【Spring】Spring Framework Reference Documentation中文版13

PROPAGATION_REQUIRES_NEW

PROPAGATION_REQUIRES_NEW, in contrast to PROPAGATION_REQUIRED, uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions are different and hence can commit or roll back independently, with an outer transaction not affected by an inner transaction’s rollback status.

PROPAGATION_REQUIRES_NEW和PROPAGATION_REQUIRED相反,使用一个全面独立的事务对于每个影响的事务范围。因此,底层的物理事务是不同的并且可以独立提交或回滚,因为一个外部事务不会被内部事务的回滚状态影响。

Nested

嵌入

PROPAGATION_NESTED uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions. See Spring’s DataSourceTransactionManager.

PROPAGATION_NESTED使用一个单独的物理事务使用多个保存点可以被回滚。这样的局部回滚允许一个内部的事务范围来引起这个范围的回滚,外部事务可以继续物理事务尽管一些行为已经被回滚。这样的设置通常匹配JDBC的保存点,因此将只会影响JDBC资源的事务。见spring的DataSourceTransactionManager。

17.5.8 Advising transactional operations

advising事务操作

Suppose you want to execute both transactional and some basic profiling advice. How do you effect this in the context of <tx:annotation-driven/>?

假设你希望执行事务和一些基本的advice。如何使用<tx:annotation-driven/>的上下文进行配置?

When you invoke the updateFoo(Foo) method, you want to see the following actions:

当你调用updateFoo方法,你希望看到下面的行为:

    Configured profiling aspect starts up.

开始配置性能分析

    Transactional advice executes.

事务advice的执行

    Method on the advised object executes.

在advised的object上的方法的执行

    Transaction commits.

事务提交

    Profiling aspect reports exact duration of the whole transactional method invocation.

性能分析方面报告精确到整个事务方法的调用

[Note]

注意

This chapter is not concerned with explaining AOP in any great detail (except as it applies to transactions). See Chapter 11, Aspect Oriented Programming with Spring for detailed coverage of the following AOP configuration and AOP in general.

这节不关系解释AOP到一个很详细的位置(除他应用事务之外)。见章节11,面向切面编程有关spring来了解细节有关下面的AOP配置和AOP的使用。

Here is the code for a simple profiling aspect discussed above. The ordering of advice is controlled through the Ordered interface. For full details on advice ordering, see the section called “Advice ordering”. .

这里是一些代码对于简单的性能方面的讨论如上。advice的顺序被控制通过Ordered接口。对于advice顺序的细节,见章节“advice的顺序”

package x.y;

import org.aspectj.lang.ProceedingJoinPoint;

import org.springframework.util.StopWatch;

import org.springframework.core.Ordered;

public class SimpleProfiler implements Ordered {

    private int order;

    // allows us to control the ordering of advice

    public int getOrder() {

        return this.order;

    }

    public void setOrder(int order) {

        this.order = order;

    }

    // this method is the around advice

    public Object profile(ProceedingJoinPoint call) throws Throwable {

        Object returnValue;

        StopWatch clock = new StopWatch(getClass().getName());

        try {

            clock.start(call.toShortString());

            returnValue = call.proceed();

        } finally {

            clock.stop();

            System.out.println(clock.prettyPrint());

        }

        return returnValue;

    }

}

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- this is the aspect -->

    <bean id="profiler" class="x.y.SimpleProfiler">

        <!-- execute before the transactional advice (hence the lower order number) -->

        <property name="order" __value="1"__/>

    </bean>

    <tx:annotation-driven transaction-manager="txManager" __order="200"__/>

    <aop:config>

            <!-- this advice will execute around the transactional advice -->

            <aop:aspect id="profilingAspect" ref="profiler">

                <aop:pointcut id="serviceMethodWithReturnValue"

                        expression="execution(!void x.y..*Service.*(..))"/>

                <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>

            </aop:aspect>

    </aop:config>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>

        <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>

        <property name="username" value="scott"/>

        <property name="password" value="tiger"/>

    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource"/>

    </bean>

</beans>

The result of the above configuration is a fooService bean that has profiling and transactional aspects applied to it in the desired order. You configure any number of additional aspects in similar fashion.

上面的配置的结果是fooService的bean有性能分析和事务方面应用在期望的顺序。你配置任何数量额外的方面以相同的形式。

The following example effects the same setup as above, but uses the purely XML declarative approach.

下面的例子和上面的配置有相同的效果,但是使用了纯净的xml声明的方式。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- the profiling advice -->

    <bean id="profiler" class="x.y.SimpleProfiler">

        <!-- execute before the transactional advice (hence the lower order number) -->

        __<property name="order" value="1__"/>

    </bean>

    <aop:config>

        <aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>

        <!-- will execute after the profiling advice (c.f. the order attribute) -->

        <aop:advisor advice-ref="txAdvice" pointcut-ref="entryPointMethod" __order="2__"/>

        <!-- order value is higher than the profiling aspect -->

        <aop:aspect id="profilingAspect" ref="profiler">

            <aop:pointcut id="serviceMethodWithReturnValue"

                    expression="execution(!void x.y..*Service.*(..))"/>

            <aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/>

        </aop:aspect>

    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="txManager">

        <tx:attributes>

            <tx:method name="get*" read-only="true"/>

            <tx:method name="*"/>

        </tx:attributes>

    </tx:advice>

    <!-- other <bean/> definitions such as a DataSource and a PlatformTransactionManager here -->

</beans>

The result of the above configuration will be a fooService bean that has profiling and transactional aspects applied to it in that order. If you want the profiling advice to execute after the transactional advice on the way in, and before the transactional advice on the way out, then you simply swap the value of the profiling aspect bean’s order property so that it is higher than the transactional advice’s order value.

上面配置的结果是fooService的bean已经作为事务的方面应用以一定的顺序。如果你希望切面的advice来执行在事务advice之后在进入的时候,并且在事务advice之前在出去的时候,你简单的交换方面的bean的顺序的值以使得高于事务advice的顺序值。

You configure additional aspects in similar fashion.

你可以配置额外的方面以类似的方式。

17.5.9 Using @Transactional with AspectJ

使用AspectJ配合@Transactional

It is also possible to use the Spring Framework’s @Transactional support outside of a Spring container by means of an AspectJ aspect. To do so, you first annotate your classes (and optionally your classes' methods) with the @Transactional annotation, and then you link (weave) your application with the org.springframework.transaction.aspectj.AnnotationTransactionAspect defined in the spring-aspects.jar file. The aspect must also be configured with a transaction manager. You can of course use the Spring Framework’s IoC container to take care of dependency-injecting the aspect. The simplest way to configure the transaction management aspect is to use the <tx:annotation-driven/> element and specify the mode attribute to aspectj as described in Section 17.5.6, “Using @Transactional”. Because we’re focusing here on applications running outside of a Spring container, we’ll show you how to do it programmatically.

也可以使用spring框架的@Transactional支持spring容器外通过AspectJ的方面。为了这么做,你首先声明你的类(和可选的你的类的方法)使用@Transactional注解,然后你连接你的应用和定义在spring-aspects.jar文件中的org.springframework.transaction.aspectj.AnnotationTransactionAspect。方面也必须配置使用事务管理器。你也可以使用spring框架的IOC容器来处理依赖注入的方面。最简单的方式来配置事务管理器方面时使用<tx:annotation-driven/>元素和指定mode属性对于aspectj描述在17.5.6节“使用@Transactional”。因为我们在这关注于应用在spring容器外运行,我们将展示你如何编程来实现。

[Note]

注意

Prior to continuing, you may want to read Section 17.5.6, “Using @Transactional” and Chapter 11, Aspect Oriented Programming with Spring respectively.

在继续之前,你可能需要分别读一下17.5.6节,“使用@Transactional”和章节11,使用spring实现面向切面的编程。

// construct an appropriate transaction manager

DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());

// configure the AnnotationTransactionAspect to use it; this must be done before executing any transactional methods

AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager);

[Note]

注意

When using this aspect, you must annotate the implementation class (and/or methods within that class), not the interface (if any) that the class implements. AspectJ follows Java’s rule that annotations on interfaces are not inherited.

当使用这个方面,你必须注解实现类(and/or类中的方法),不是类实现的任何接口。AspectJ符合Java的规则注解在接口上是不会被继承的。

The @Transactional annotation on a class specifies the default transaction semantics for the execution of any method in the class.

@Transactional注解在类指定默认的事务语义对于执行类上的任何方法。

The @Transactional annotation on a method within the class overrides the default transaction semantics given by the class annotation (if present). Any method may be annotated, regardless of visibility.

方法上的@Transactional注解在类上覆盖默认的事务语义通过给定的类注解。任何方法都可以被注解不管是否可见。

To weave your applications with the AnnotationTransactionAspect you must either build your application with AspectJ (see the AspectJ Development Guide) or use load-time weaving. See Section 11.8.4, “Load-time weaving with AspectJ in the Spring Framework” for a discussion of load-time weaving with AspectJ.

为了处理你的应用使用AnnotationTransactionAspect,你必须构建你的应用使用AspectJ(见AspectJ的开发指南)或使用加载时处理。见11.8.4节,“在spring框架中使用AspectJ加载时处理”来讨论使用AspectJ在加载时处理。

17.6 Programmatic transaction management

编程事务管理

The Spring Framework provides two means of programmatic transaction management:

spring框架提供了两种方式对于编程事务管理:

    Using the TransactionTemplate.

使用TransactionTemplate

    Using a PlatformTransactionManager implementation directly.

直接使用PlatformTransactionManager实现

The Spring team generally recommends the TransactionTemplate for programmatic transaction management. The second approach is similar to using the JTA UserTransaction API, although exception handling is less cumbersome.

spring小组通常建议使用TransactionTemplate对于编程事务管理。第二种方法和使用JTA UserTransaction API有些相似,尽管异常的处理有些笨重。

17.6.1 Using the TransactionTemplate

使用TransactionTemplate

The TransactionTemplate adopts the same approach as other Spring templates such as the JdbcTemplate. It uses a callback approach, to free application code from having to do the boilerplate acquisition and release of transactional resources, and results in code that is intention driven, in that the code that is written focuses solely on what the developer wants to do.

TransactionTemplate采用了相同的方法和其他的spring模板一样如JdbcTemplate。他使用了回调的方式,对于开放应用代码来自引用和事务资源的发布版,导致代码是面向意向的,代码的书写强调开发者希望实现的。

[Note]

注意

As you will see in the examples that follow, using the TransactionTemplate absolutely couples you to Spring’s transaction infrastructure and APIs. Whether or not programmatic transaction management is suitable for your development needs is a decision that you will have to make yourself.

你将会在下面的例子中看到,使用TransactionTemplate使得你将事务架构和API结合在一起。不管编程事务管理是否适合你的开发需要你自己来做决定。

Application code that must execute in a transactional context, and that will use the TransactionTemplate explicitly, looks like the following. You, as an application developer, write a TransactionCallback implementation (typically expressed as an anonymous inner class) that contains the code that you need to execute in the context of a transaction. You then pass an instance of your custom TransactionCallback to the execute(..) method exposed on the TransactionTemplate.

应用代码必须在事务上下文中执行,并且将明确使用TransactionTemplate,看上去如下。你作为应用开发者,书写TransactionCallback实现(通常作为一个匿名内部类)包含你需要在事务上下文中执行的代码。然后你传递你自定义的TransactionCallback实例给execute方法来自TransactionTemplate。

public class SimpleService implements Service {

    // single TransactionTemplate shared amongst all methods in this instance

    private final TransactionTemplate transactionTemplate;

    // use constructor-injection to supply the PlatformTransactionManager

    public SimpleService(PlatformTransactionManager transactionManager) {

        Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");

        this.transactionTemplate = new TransactionTemplate(transactionManager);

    }

    public Object someServiceMethod() {

        return transactionTemplate.execute(new TransactionCallback() {

            // the code in this method executes in a transactional context

            public Object doInTransaction(TransactionStatus status) {

                updateOperation1();

                return resultOfUpdateOperation2();

            }

        });

    }

}

If there is no return value, use the convenient TransactionCallbackWithoutResult class with an anonymous class as follows:

如果没有返回值,使用方便的TransactionCallbackWithoutResult类和一个匿名类如下:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

    protected void doInTransactionWithoutResult(TransactionStatus status) {

        updateOperation1();

        updateOperation2();

    }

});

Code within the callback can roll the transaction back by calling the setRollbackOnly() method on the supplied TransactionStatus object:

使用回调代码可以回滚事务通过调用setRollbackOnly方法在提供的TransactionStatus上。

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

    protected void doInTransactionWithoutResult(TransactionStatus status) {

        try {

            updateOperation1();

            updateOperation2();

        } catch (SomeBusinessExeption ex) {

            status.setRollbackOnly();

        }

    }

});

Specifying transaction settings

指定事务设置

You can specify transaction settings such as the propagation mode, the isolation level, the timeout, and so forth on the TransactionTemplate either programmatically or in configuration. TransactionTemplate instances by default have the default transactional settings. The following example shows the programmatic customization of the transactional settings for a specific TransactionTemplate:

你可以指定事务设置例如传播模式、隔离级别、超时等等在TransactionTemplate上或在配置中。TransactionTemplate实例默认有默认的事务配置。下面的例子展示了编程的自定义对于事务设置对于特定的TransactionTemplate。

public class SimpleService implements Service {

    private final TransactionTemplate transactionTemplate;

    public SimpleService(PlatformTransactionManager transactionManager) {

        Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");

        this.transactionTemplate = new TransactionTemplate(transactionManager);

        // the transaction settings can be set here explicitly if so desired

        this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);

        this.transactionTemplate.setTimeout(30); // 30 seconds

        // and so forth...

    }

}

The following example defines a TransactionTemplate with some custom transactional settings, using Spring XML configuration. The sharedTransactionTemplate can then be injected into as many services as are required.

下面的例子定义了一个TransactionTemplate使用一些自定义的事务设置,使用了spring的xml配置。sharedTransactionTemplate可以被注入到需要的服务中。

<bean id="sharedTransactionTemplate"

        class="org.springframework.transaction.support.TransactionTemplate">

    <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>

    <property name="timeout" value="30"/>

</bean>"

Finally, instances of the TransactionTemplate class are threadsafe, in that instances do not maintain any conversational state. TransactionTemplate instances do however maintain configuration state, so while a number of classes may share a single instance of a TransactionTemplate, if a class needs to use a TransactionTemplate with different settings (for example, a different isolation level), then you need to create two distinct TransactionTemplate instances.

最后,TransactionTemplate类的实例是线程安全的,在实例不包含任何会话状态。TransactionTemplate实例包含配置状态,因此一些类可以共享一个单独的TransactionTemplate实例,如果一个类需要使用TransactionTemplate包含不同的设置(例如,一个不同的隔离级别),你需要创建两个TransactionTemplate实例。

17.6.2 Using the PlatformTransactionManager

使用PlatformTransactionManager

You can also use the org.springframework.transaction.PlatformTransactionManager directly to manage your transaction. Simply pass the implementation of the PlatformTransactionManager you are using to your bean through a bean reference. Then, using the TransactionDefinition and TransactionStatus objects you can initiate transactions, roll back, and commit.

你也可以直接使用org.springframework.transaction.PlatformTransactionManager来管理你的事务。简单传递PlatformTransactionManager的实现你使用你的bean通过一个bean的引用。然后,使用TransactionDefinition和TransactionStatus你可以初始化事务、回滚和提交。

DefaultTransactionDefinition def = new DefaultTransactionDefinition();

// explicitly setting the transaction name is something that can only be done programmatically

def.setName("SomeTxName");

def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);

try {

    // execute your business logic here

}

catch (MyException ex) {

    txManager.rollback(status);

    throw ex;

}

txManager.commit(status);

17.7 Choosing between programmatic and declarative transaction management

选择编程和声明式事务管理

Programmatic transaction management is usually a good idea only if you have a small number of transactional operations. For example, if you have a web application that require transactions only for certain update operations, you may not want to set up transactional proxies using Spring or any other technology. In this case, using the TransactionTemplate may be a good approach. Being able to set the transaction name explicitly is also something that can only be done using the programmatic approach to transaction management.

编程事务管理通常是一个好的注意如果你有一些事务操作。例如,如果你有一个web应用需要事务在更新操作中,你可能不需要使用spring来设置事务代理或其他技术。在这种情况,使用TransactionTemplate可能就是一个好的方式。可以明确额设置事务的名字可以通过使用编程范式对于事务管理。

On the other hand, if your application has numerous transactional operations, declarative transaction management is usually worthwhile. It keeps transaction management out of business logic, and is not difficult to configure. When using the Spring Framework, rather than EJB CMT, the configuration cost of declarative transaction management is greatly reduced.

另一方面,如果你的应用有多个事务操作,声明事务管理通常是好的。他保证事务管理在业务逻辑之外,并且很容易配置。当使用spring框架,而不是EJB CMT,声明式事务管理的配置会减少很多。

17.8 Transaction bound event

事务约束事件

As of Spring 4.2, the listener of an event can be bound to a phase of the transaction. The typical example is to handle the event when the transaction has completed successfully: this allows events to be used with more flexibility when the outcome of the current transaction actually matters to the listener.

在spring4.2中,事件监听器可以绑定到事务的一个部分。通常例子就是处理时间当事务已经成功完成后:这允许事件被使用更加的方便当当前的事务实际在监听器之外时。

Registering a regular event listener is done via the @EventListener annotation. If you need to bind it to the transaction use @TransactionalEventListener. When you do so, the listener will be bound to the commit phase of the transaction by default.

注册一个普通的事件监听器通过@EventListener注解。如果你需要绑定到事务通过使用@TransactionalEventListener。当你这么做,监听器将默认绑定到事务的提交阶段。

Let’s take an example to illustrate this concept. Assume that a component publish an order created event and we want to define a listener that should only handle that event once the transaction in which it has been published as committed successfully:

让我们来考虑一个例子来说明这个内容。假设一个组件发表创建事件并且我们希望定义一个监听器应当只被处理事件一旦事务被发布成功提交:

@Component

public class MyComponent {

    @TransactionalEventListener

    public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {

          ...

    }

}

The TransactionalEventListener annotation exposes a phase attribute that allows to customize to which phase of the transaction the listener should be bound to. The valid phases are BEFORE_COMMIT, AFTER_COMMIT (default), AFTER_ROLLBACK and AFTER_COMPLETION that aggregates the transaction completion (be it a commit or a rollback).

TransactionalEventListener注解暴露了phase属性允许你自定义事务的什么阶段和监听器绑定。合法的阶段是BEFORE_COMMIT、AFTER_COMMIT(默认值)、AFTER_ROLLBACK和AFTER_COMPLETION组成的事务的完成(是提交还是回滚)。

If no transaction is running, the listener is not invoked at all since we can’t honor the required semantics. It is however possible to override that behaviour by setting the fallbackExecution attribute of the annotation to true.

如果没有事务在运行,监听器不会被调用自从我们不能使用required语义。可以覆盖设置的行为通过注解的fallbackExecution属性设置为true。

17.9 Application server-specific integration

特定应用服务器的集成

Spring’s transaction abstraction generally is application server agnostic. Additionally, Spring’s JtaTransactionManager class, which can optionally perform a JNDI lookup for the JTA UserTransaction and TransactionManager objects, autodetects the location for the latter object, which varies by application server. Having access to the JTA TransactionManager allows for enhanced transaction semantics, in particular supporting transaction suspension. See the JtaTransactionManager javadocs for details.

spring的事务抽象通常对应用服务器是不可知的。此外,spring的JtaTransactionManager类,可以选择使用JNDI查找对于JTA UserTransaction和TransactionManager,自动探测位置对于后续的object,对于不同的应用服务器。访问JTA TransactionManager允许增强事务语义,特别是支持事务挂起。见JtaTransactionManager的javadocs来了解细节。

Spring’s JtaTransactionManager is the standard choice to run on Java EE application servers, and is known to work on all common servers. Advanced functionality such as transaction suspension works on many servers as well — including GlassFish, JBoss and Geronimo — without any special configuration required. However, for fully supported transaction suspension and further advanced integration, Spring ships special adapters for WebLogic Server and WebSphere. These adapters are discussed in the following sections.

spring的JtaTransactionManager是标准的选择来运行JavaEE应用服务器并且被大部分通用服务器知道。高级的功能例如事务挂起可以在多个服务器上运行————包括GlassFish、JBoss和Geronimo————不需要特殊的配置。然而对于全部的事务挂起支持和更高级的集成,是WebLogic服务器和WebSphere。他们的适配将在下面的章节中讨论。

For standard scenarios, including WebLogic Server and WebSphere, consider using the convenient <tx:jta-transaction-manager/> configuration element. When configured, this element automatically detects the underlying server and chooses the best transaction manager available for the platform. This means that you won’t have to configure server-specific adapter classes (as discussed in the following sections) explicitly; rather, they are chosen automatically, with the standard JtaTransactionManager as default fallback.

对于标准的场景,包括WebLogic和WebSphere,考虑使用方便的<tx:jta-transaction-manager/>配置元素。当配置后,这个元素自动探测底层服务器并且选择最好的事务管理对于平台可用。这意味这你不能配置服务器特定的适配器类(就像下面的章节的讨论的),他们被自动选择,默认是标准的JtaTransactionManager。

17.9.1 IBM WebSphere

On WebSphere 6.1.0.9 and above, the recommended Spring JTA transaction manager to use is WebSphereUowTransactionManager. This special adapter leverages IBM’s UOWManager API, which is available in WebSphere Application Server 6.0.2.19 and later and 6.1.0.9 and later. With this adapter, Spring-driven transaction suspension (suspend/resume as initiated by PROPAGATION_REQUIRES_NEW) is officially supported by IBM!

在WebSphere6.1.0.9及以上的版本,推荐使用Spring的JTA事务管理是WebSphereUowTransactionManager。特殊的适配器使用了IBM的UOWManager API,在WebSphere应用服务器的6.0.2.19及以后的版本及6.1.0.9及以后的版本中。使用这个适配器,基于spring的事务挂起(挂起和恢复是通过PROPAGATION_REQUIRES_NEW发起的)被官方的IBM支持。

17.9.2 Oracle WebLogic Server

On WebLogic Server 9.0 or above, you typically would use the WebLogicJtaTransactionManager instead of the stock JtaTransactionManager class. This special WebLogic-specific subclass of the normal JtaTransactionManager supports the full power of Spring’s transaction definitions in a WebLogic-managed transaction environment, beyond standard JTA semantics: Features include transaction names, per-transaction isolation levels, and proper resuming of transactions in all cases.

在WebLogic服务器9.0及以上的版本,你通常会使用WebLogicJtaTransactionManager代替JtaTransactionManager类。这个特殊的JtaTransactionManager的WebLogic子类支持全功能的spring事务定义在WebLogic管理的事务环境中,通过标准的JTA语义:特性包括事务的名字、每个事务的隔离级别和适当的事务恢复在所有的例子中。

17.10 Solutions to common problems

对于通常问题的解决方案

17.10.1 Use of the wrong transaction manager for a specific DataSource

对于特定的数据源使用错误的事务管理

Use the correct PlatformTransactionManager implementation based on your choice of transactional technologies and requirements. Used properly, the Spring Framework merely provides a straightforward and portable abstraction. If you are using global transactions, you must use the org.springframework.transaction.jta.JtaTransactionManager class (or an application server-specific subclass of it) for all your transactional operations. Otherwise the transaction infrastructure attempts to perform local transactions on resources such as container DataSource instances. Such local transactions do not make sense, and a good application server treats them as errors.

使用正确的PlatformTransactionManager实现基于你对传统技术和需求的选择。使用合适,spring框架仅仅提供了一个简单直接的抽象。如果你使用全局事务,你必须使用org.springframework.transaction.jta.JtaTransactionManager类(或一个特定的应用服务器的子类)对于你的事务操作。此外事务架构尝试执行本地事务在资源上例如容器数据源实例。这样的本地事务没有意义,并且一个好的应用服务会作为错误跟踪她们呢。

17.11 Further Resources

更多的资源

For more information about the Spring Framework’s transaction support:

了解spring框架事务支持的更多信息:

    Distributed transactions in Spring, with and without XA is a JavaWorld presentation in which Spring’s David Syer guides you through seven patterns for distributed transactions in Spring applications, three of them with XA and four without.

spring中的分布式事务,使用或不使用XA是一个Java的表现在spring的David Syer指导你通过七种方式处理分布式事务在spring的应用中,三个需要XA而另外四个不需要。

    Java Transaction Design Strategies is a book available from InfoQ that provides a well-paced introduction to transactions in Java. It also includes side-by-side examples of how to configure and use transactions with both the Spring Framework and EJB3.

Java是事务设计策略是在InfoQ中可用提供了很好的介绍对于Java事务。他也包括并行的例子关于如何配置和使用事务通过spring框架和EJB。

18. DAO support

DAO支持

18.1 Introduction

介绍

The Data Access Object (DAO) support in Spring is aimed at making it easy to work with data access technologies like JDBC, Hibernate, JPA or JDO in a consistent way. This allows one to switch between the aforementioned persistence technologies fairly easily and it also allows one to code without worrying about catching exceptions that are specific to each technology.

在spring中的DAO支持目标是使得数据的访问更加简单通过JDBC、Hibernate、JPA或JDO以一致的方式。这允许可以很方便的切换上面的提到的这些技术并且允许不用关心特定的技术的异常处理。

18.2 Consistent exception hierarchy

一致的异常结构

Spring provides a convenient translation from technology-specific exceptions like SQLException to its own exception class hierarchy with the DataAccessException as the root exception. These exceptions wrap the original exception so there is never any risk that one might lose any information as to what might have gone wrong.

spring提供了一个方便的方式来将技术特定的异常例如SQLException转换为他们自己的异常类结构使用DataAccessException作为根异常。这样的异常包裹原始的异常因此这不会有任何风险这样当错误发生时任何信息都不会丢失。

In addition to JDBC exceptions, Spring can also wrap Hibernate-specific exceptions, converting them to a set of focused runtime exceptions (the same is true for JDO and JPA exceptions). This allows one to handle most persistence exceptions, which are non-recoverable, only in the appropriate layers, without having annoying boilerplate catch-and-throw blocks and exception declarations in one’s DAOs. (One can still trap and handle exceptions anywhere one needs to though.) As mentioned above, JDBC exceptions (including database-specific dialects) are also converted to the same hierarchy, meaning that one can perform some operations with JDBC within a consistent programming model.

对于JDBC异常,spring可以包裹特定的Hibernate异常,将他们转换为一系列运行时异常(相同的规则对于JDO和JPA异常)。这允许我们处理大部分持久化异常,有些事不可恢复,在适当的层中不需要使用复制样板文件catch-throw块和在DAO中定义异常。(可以抓捕和处理异常更加需要)。上面提到的,JDBC异常(包括特定数据库会话)也可以转换到相同的结构,意味着可以使用JDBC处理一些操作通过一致的编程模型。

The above holds true for the various template classes in Springs support for various ORM frameworks. If one uses the interceptor-based classes then the application must care about handling HibernateExceptions and JDOExceptions itself, preferably via delegating to SessionFactoryUtils’ `convertHibernateAccessException(..) or convertJdoAccessException() methods respectively. These methods convert the exceptions to ones that are compatible with the exceptions in the org.springframework.dao exception hierarchy. As JDOExceptions are unchecked, they can simply get thrown too, sacrificing generic DAO abstraction in terms of exceptions though.

上面的对于不同的模板类有效在spring中支持不同的ORM框架。如果使用基于拦截器类然后应用必须考虑处理HibernateExceptions和JDOExceptions异常本身,最好明确通过授权给SessionFactoryUtils’的convertHibernateAccessException或convertJdoAccessException方法。这些方法转换异常匹配org.springframework.dao exception的结构。由于JDOExceptions是非检查的,他们可以简单的抛出异常,在异常中放弃一个通用的DAO抽象。

The exception hierarchy that Spring provides can be seen below. (Please note that the class hierarchy detailed in the image shows only a subset of the entire DataAccessException hierarchy.)

这些异常结构中spring支持的如下。(请注意类结构的细节在图中的展示只是整个DataAccessException结构中的一部分。)

【Spring】Spring Framework Reference Documentation中文版13

18.3 Annotations used for configuring DAO or Repository classes

注解使用来配置DAO或Repository类

The best way to guarantee that your Data Access Objects (DAOs) or repositories provide exception translation is to use the @Repository annotation. This annotation also allows the component scanning support to find and configure your DAOs and repositories without having to provide XML configuration entries for them.

最好的方式是你的DAO或Repository提供异常转换通过使用spring的注解。这个注解也允许组件扫描支持来查找和配置你的DAO和Repository不需要提供整个xml配置。

@Repository

public class SomeMovieFinder implements MovieFinder {

    // ...

}

Any DAO or repository implementation will need to access to a persistence resource, depending on the persistence technology used; for example, a JDBC-based repository will need access to a JDBC DataSource; a JPA-based repository will need access to an EntityManager. The easiest way to accomplish this is to have this resource dependency injected using one of the @Autowired,, @Inject, @Resource or @PersistenceContext annotations. Here is an example for a JPA repository:

任何DAO或Repository实现将需要访问持久化资源,依赖于持久化技术的使用;例如,基于基于JDBC的Repository将需要访问JDBC数据源,一个基于JPA的Repository需要访问EntityManager。最简单的方式来完成时有一个资源依赖注入使用@Autowired、@Inject、@Resource或@PersistenceContext注解。这里有一个使用JPA Repository的例子。

@Repository

public class JpaMovieFinder implements MovieFinder {

    @PersistenceContext

    private EntityManager entityManager;

    // ...

}

If you are using the classic Hibernate APIs than you can inject the SessionFactory:

如果你使用普通的Hibernate的API注入到SessionFactory:

@Repository

public class HibernateMovieFinder implements MovieFinder {

    private SessionFactory sessionFactory;

    @Autowired

    public void setSessionFactory(SessionFactory sessionFactory) {

        this.sessionFactory = sessionFactory;

    }

    // ...

}

Last example we will show here is for typical JDBC support. You would have the DataSource injected into an initialization method where you would create a JdbcTemplate and other data access support classes like SimpleJdbcCall etc using this DataSource.

最后的例子将展示通常的JDBC支持。你将注入一个数据源到初始化方法当你创建一个JdbcTemplate和其他数据访问支持类例如SimpleJdbcCall等等使用这个数据源。

@Repository

public class JdbcMovieFinder implements MovieFinder {

    private JdbcTemplate jdbcTemplate;

    @Autowired

    public void init(DataSource dataSource) {

        this.jdbcTemplate = new JdbcTemplate(dataSource);

    }

    // ...

}

[Note]

注意

Please see the specific coverage of each persistence technology for details on how to configure the application context to take advantage of these annotations.

请见特定持久化技术的细节及如何配置应用上下文通过使用这些注解。

继续阅读