spring 事务管理文档意译(1/5)

2 篇文章 0 订阅
2 篇文章 0 订阅

翻译只是为了更好的理解文档

spring 事务管理文档意译: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html


12. 事务管理

12.1 spring事务管理介绍

完善的事务支持是使用spring的最主要原因之一,spring为事务管理提供统一抽象,带来这些好处:

  • 为不同的事务api提供统一编程模型,JTA, JDBC, JPA,Hibernate,JDO
  • 支持声明式事务
  • 提供更简单的编程式事务管理api,相比JTA这种
  • 与spring数据存取服务非常好的整合
接下来要描述spring事务管理提供的价值和技术,最佳实践

  • spring事务管理的优点:你为什么使用spring事务管理而不是ejb容器管理事务,或者hibernate这种本地的专有api
  • 了解spring事务管理:核心类,如何配置数据源
  • 事务资源:应用代码如何创建,重用和清理事务资源
  • 声明式事务管理:对声明式事务管理的支持
  • 编程式事务管理:对编程式事务管理的支持
12.2 spring事务管理模型的好处

传统上,j2ee开发者做事务管理有两个选择:全局和本地事务,每个都很有局限。下面要回顾一下这两种方案,然后讨论一下spring事务管理如何解决两种方案存在的问题.

12.2.1 全局事务

全局事务让你可以管理多个事务资源,比如关系型数据库和消息队列,应用服务器通过JTA来管理全局事务,这个api用起来很麻烦(一部分原因是他的异常模型),还有,JTA的UserTransaction需要从JNDI获取,就是说你要用JTA,你就要用JNDI。使用全局事务会限制应用代码的复用,通常JTA只能在应用服务器环境中使用。

之前,使用JTA的推荐方式是使用EJB CMT(container managed transaction),CMT是一种声明式事务管理(另一种是编程式事务管理)。EJB CMT消除了使用事务相关的JNDI查找,但是EJB本身的使用中需要JNDI。CMT最明显的缺点是绑定了JTA和应用服务器环境。只有在EJB服务器中编写业务逻辑才能使用CMT,或者至少你要使用一个EJB facade。这个缺点太明显,这个方案不是太多人用。尤其是还有非常好的声明式替代方案(译者注:当然是我们的spring事务管理方案喽)

12.2.2 本地事务

本地事务和具体资源相关。例如jdbc相关的事务,本地事务更容易使用,但是缺点也很明显,不能跨多个事务资源使用。比如说用jdbc连接管理的事务不能在JTA全局事务中使用,因为事务管理不牵涉到服务器资源,他不能保证跨多资源数据的正确性。也要注意:多数应用其实只使用一个事务资源(译者注:比如数据库单库),还有一个缺点是他对非事务的编程侵入性太大.


12.2.3 spring统一编程模型

spring 解决了全局和本地事务的缺点。他让应用开发者在任何环境使用统一的编程模型。你只要编写一次代码,不同环境的不同事务管理模型都能管用。spring提供了声明式和编程式事务两种用法。大多数用户都用声明式,我们也推荐这种用法

如果使用编程式事务管理,开发者使用spring的事务抽象,它可以运行在任何底层事务管理机制上。使用推荐的声明式事务管理,开发者可以只写一点,甚至不用写任何事物管理的代码,这样都不依赖于spring的事务管理api,或者任何其他的事务管理api

需要给事务管理弄个应用服务器么?

spring事务管理改变了企业级java应用需要一个应用服务器的情况。

你不需要为了EJB声明式事务引入应用服务器。实际上,即使你的应用服务器有强大的JTA支持,你也会认为,相比EJB CMT,spring声明式事务提供更强大的功能,更高效的编程模型。

只有在你需要处理跨资源的事务时,你才需要应用服务器的JTA支持,多数应用不需要这个支持。很多高端应用使用单个高扩展的数据库,比如ORACLE RAC。例如Atomikos Transactions 还有JOTM是其他的解决方案。当然,你可能需要应用服务器提供的JMS和JCA服务。

Spring让你可以选择何时扩展你的应用,假设到一个应用服务器上。只有使用EJB CMT或者JTA,写大量本地事务代码,如果要纳入全局事务管理,还得重写一堆代码,这种日子成为过去了。用spring,你只需要定义几个bean在配置文件里面,而不是写一堆代码。

12.3 理解spring事务

理解spring事务关键是事务策略的概念。事务策略是由org.springframework.transaction.PlatformTransactionManager interface定义的:

public interface PlatformTransactionManager {

    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

    void commit(TransactionStatus status) throws TransactionException;

    void rollback(TransactionStatus status) throws TransactionException;
}

虽然可以以编程的形式在代码里面使用,这主要还是作为服务提供接口(SPI)使用。因为 PlatformTransactionManager 是一个接口,很容易被mocked或者stubbed,如果有必要的话。他没有被绑定在JNDI之类东东上。PlatformTransactionManager 的实现类和其他的bean一样定义在spring IOC容器内。这样即使是使用JTA,也值得使用spring事务抽象一层(和spring容器整合),通过spring事务,JTA事务代码容易测试的多,比直接使用JTA。

为了遵守spring的哲学, TransactionException 是可以被 PlatformTransactionManager 接口中的任何方法抛出的,他是unchecked类型的,是 java.lang.RuntimeException 的子类。事务的失败几乎总是致命的,很少的时候,应用代码可以在事务失败的情况下恢复,开发者还是可以选择捕获异常 TransactionException. 关键点是开发者有选择的自由。

 getTransaction(..) 方法总是返回 TransactionStatus 对象, 具体取决于 TransactionDefinition 参数. 返回的 TransactionStatus 可能表示一个新的事务, 如果在调用栈里面已经有一个匹配的事务,可能表示一个已有的事务 。后者情况的含义是,在java ee事务上下文中, TransactionStatus 是和一个执行线程绑定的。

 TransactionDefinition 接口指定了:

  • 隔离级别(Isolation): 事务和其他事务的隔离的程度。例如这个事务是否能够看到其他事务的未提交写。
  • 传播特性(Propagation): 一般来讲,所有在事务定义范围内,执行的代码都在这个事务内运行. 但是,如果在一个事务上下文已经存在的情况下,执行另外一个定义了事务边界的方法,你可以具体指定这个方法的事务行为。比如说,代码可以在已有事务中执行(通常这么做);或者已有的事务可以被挂起,创建一个新的事务。spring提供了所有EJB CMT提供的所有事务传播特性。要了解spring中事务传播特性语义,参阅 Section 12.5.7, “Transaction propagation”.
  • 超时(Timeout): 事务运行多久不结束,就会被超时,然后被事务管理机制自动回滚。
  • 只读特性(Read-only status):如果代码只读数据,而不修改,可以使用只读事务 只读事务在某些情况下是一种优化措施,比如你使用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或者其他事务解决方案至关重要。

 TransactionStatus 接口提供了通过编码,控制事务执行,获得执行情况的简单方式。这个概念应该不陌生,各种事务api都有类似概念:

public interface TransactionStatus extends SavepointManager {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();

}

无论是不是对spring的声明式或者编程式事务管理熟悉,正确的定义 PlatformTransactionManager 的实现类非常非常非常重要. 你一般是通过依赖注入定义的。

PlatformTransactionManager 实现类通常依赖你使用的环境: JDBC, JTA, Hibernate, 或者其他 。下面的例子是你如何定义一个本地 PlatformTransactionManager 实现. (这个例子是基于简单的JDBC.)

You define a JDBC DataSourcer

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

相关的 PlatformTransactionManager bean会引用 DataSource 的bean. 大概是这样:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

如果你在Java EE容器中,使用JTA。你会使用一个容器通过JNDI获得的的 DataSource, 然后使用Spring的 JtaTransactionManager. 这个是配合 JTA and 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>

 JtaTransactionManager 不需要引用 DataSource, 或者任何具体的数据源, 因为他使用容器统一事务管理机制。

[Note]

上面的 dataSource bean定义使用  jee 命名空间里面的 <jndi-lookup/> 标签. 更多schema相关配置的信息,参考Chapter 34, XML Schema-based configuration, 更多 <jee/> 标签信息参考Section 34.2.3, “the jee schema”.

你还可以很容易的使用Hibernate本地事务,下面的例子会讲。例子里面,你可以定义一个Hibernate的 LocalSessionFactoryBean,通过这个bean,你可以获得Hibernate的 Session 实例。

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

[Note]

如果非JTA事务管理器使用的 DataSource, 是通过JNDI查找得到的,并且由Java EE容器管理的, 那么这个数据源就走不到事务,因为spring事务管理而不是Java EE来管理这个事务.

在这个例子里面, txManager bean 是 HibernateTransactionManager 类型. 类似 DataSourceTransactionManager 需要持有DataSource的引用。  HibernateTransactionManager 需要引用 SessionFactory.

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.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.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

如果你使用Hibernate和Java EE 容器同时管理的 JTA 事务, 那么你只需要使用相同的 JtaTransactionManager ,这个和先前JTA for JDBC的例子一样。

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

如果使用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.

所有的例子中,应用层代码都不用改,你只要修改配置,就可以改变事务管理的方式。就算是从本地事务迁移到全局事务处理,或者反过来,都只要该配置.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值