全局事务

全局事务支持对多个事务性资源的操作,通常是关系型数据库和消息队列。应用服务器通过JTA管理全局性事务,API非常烦琐。UserTransaction通常需要从JNDI获取,意味着需要与JNDI绑定在一起,且JTA一般只在应用服务器可用,降低了应用代码的可重用性。

本地事务

本地事务面向具体的资源,例如与JDBC连接关联的事务。本地事务易于使用,但不能跨多个事务性资源。使用JDBC管理事务的代码不能在全局JTA事务中运行,因此不能确保跨多个资源的正确性。且本地事务侵入了编程模型。

Spring的一致性编程模型

Spring让开发者在任何环境下都可以使用一致性的编程模型,编写一次代码,就可以在不同环境的不同事务管理策略中运行。Spring提供声明式和编程式事务管理,大多数人选择声明式,这也是推荐的方式。

使用编程式事务管理时,开发者使用的是Spring框架的事务抽象,它可以运行在任何底层事务设施之上。使用声明式事务管理,开发者只需要编写少量甚至不需要编写事务相关代码,因此应用代码不依赖Spring框架事务API或其它事务API。

Spring的事务管理支持从传统规则到应用服务器的转换。

通常只有在通过EJB进行声明式事务时才真的需要应用服务器。实际上即使应用服务器有JTA的功能,也可以认为Spring框架的声明式事务比EJB CMT更加强大,更加能提高效率。

只有在应用需要跨多个资源处理事务时才需要应用服务器的JTA功能。许多高级应用使用单个高可扩展的数据库(例如Oracle RAC)来代替。独立的事务管理器也是一种方案,例如Atomikos Transactions、JOTM。应用也可能需要其它的应用服务器功能,例如JMS、JCA。

Spring框架让开发者决定何时把应用扩展为完整的应用服务器,只需要在配置文中修改某些Bean定义即可。

理解Spring框架的事务抽象

事务策略是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;
}

这是一个服务提供商接口(SPI),虽然可以在应用中编程式地使用。由于这是一个接口,所以可以很容易被模拟出来。它并不与JNDI这样的查找策略绑定在一起。它可以像其它bean一样在Spring框架IoC容器中被定义。即使在使用JTA的场景下,也可以从Spring框架的事务中受益,因为Spring中的事务代码比直接使用JTA的更加容易测试。

TransactionException是作为非检查异常抛出,它扩展java.lang.RuntimeException类,因为在Spring的角度看来,事务设施故障几乎总是致命的,很少情况下应用可以从事务故障中恢复。开发者可以选择捕获这个异常并作处理,但并不强制这样做。

getTransaction(…)根据TransactionDefinition类型的参数返回一个TransactionStatus对象,所返回的对象可能代表一个新的事务,也可能是一个当前调用栈中已经存在的事务。后一种情况表示,在使用Java EE事务上下文时,一个TransactionStatus是与执行线程关联的。

TransactionDefinition接口

TransactionDefinition接口指定了:

  • 隔离级别(Isolation):一个事务与其它事务的隔离级别,例如一个事务是否可看到其它事务未提交的写操作
  • 传播性(Propagation):一般所有在一个事务中运行的代码都会处于一个事务中,但当执行一个方法并且事务环境已经存在时,可以指定此时的行为。例如所调用方法内的代码继续运行在已经存在的事务中(常见情况),或者暂停当前事务并创建一个新的事务来运行所调用方法内的代码。Spring提供了所有EJB CMT所提供的事务传播选项。
  • 超时(Timeout):在事务超时并被底层事务设施自动回滚前,这个事务可以运行多久。
  • 只读状态(Read-only):当代码不修改数据时,可以使用只读事务。只读事务在某些场景下很有用,例如使用Hibernate时。

以上设置是标准的事务概念,指的就是事务隔离级别及其它核心事务概念。理解这些概念是使用Spring框架事务管理或其它事务解决方案的基础。

TransactionStatus接口

TransactionStatus接口为事务性代码提供控制事务执行和查询事务状态的简便方式。这些概念必须要熟悉,它们是所有事务API都共同的东西:

public interface TransactionStatus extends SavepointManager {
    boolean isNewTransaction();
    boolean hasSavepoint();
    void setRollbackOnly();
    boolean isRollbackOnly();
    void flush();
    boolean isCompleted();
}

在Spring中不管理使用声明式事务还是编程式事务,定义正确的PlatformTransactionManager实现都是必须的,一般通过DI进行定义。

PlatformTransactionManager一般只需要知道自己的工作环境:JDBC、JTA、Hibernate等等。下面是定义一个本地PlatformTransactionManager实现的例子:

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

相关的PlatformTransactionManager引用DataSource定义:

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
如果在Java EE容器中使用容器DataSource,则通过JNDI获取,并与Spring的JtaTransactionManager关联:

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

Hibernate事务配置

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

如果使用Hibernate和Java EE容器管理的JTA事务,则与前面对JDBC的JTA配置一样:

<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.transaction.jta.JtaTransactionManager"/>
如果使用JTA,则不管使用什么样的数据访问技术(JDBC、Hibernate JPA、或其它支持的技术),事务管理器定义会以相同的方式进行查找,因为JTA事务是全局性的,它会证募所有的事务性资源(JDBC connection、SessionFactory等等)。
 
通过这种配置方式,本地和全局事务的转换不需要修改应用代码,只需要在配置文件上做修改。
 

使用事务同步资源

高级别同步方式

优先使用的是Spring高级别的基于模板的持久化集成API,或使用带有事务感知的工厂Bean的原生ORM API,或者管理原生资源工厂的代理。这些事务感知的方案在内部处理对资源的创建、重用、清理、可选的资源事务同步、异常映射,因此用户代码不需要做这些工作,只需要关注于自身的持久化逻辑。一般对JDBC的访问使用的是JdbcTemplate模板方式,或ORM原生API。

低级别同步方式

JDBC的DataSourceUtils、JPA的EntityManagerFactoryUtils、Hibernate的SessionFactoryUtils、JDO的PersistemceManagerFactoryUtils是低级别的操作工具。如果应用代码需要直接处理原生持久化API的资源类型时,可以使用这些类来确保获取正确的由Spring框架管理的实例、事务被正确同步、异常被正确映射到一致的API。

例如对于传统的JDBC,可以使用下面的代码代替对DataSource的getConnection()方法的调用:

Connection conn = DataSourceUtils.getConnection(dataSource);
上面的代码,如果一个已经存在的事务已经有一个同步connection与其关联,则这个connection会被返回,否则会创建一个新的连接,并且会同步到已经存在的事务,且在后继对同一个事务的使用中可以重用这个连接。上面调用中,底层抛出的SQLException被Spring框架包装成CannotGetJdbcConnectionException,一个非检查DataAccessException,这比单纯的SQLException能够提供更多的信息,并确保跨数据库甚至跨不同持久化持久的可移植性。
 
上面的代码在没有Spring事务管理的情况下也是可用的。
 
在使用Spring的JDBC支持、JPA支持、Hibernate支持时,多数人更愿意使用Spring的事务抽象,而不是直接使用类似DataSourceUtils这样的辅助类。例如使用JdbcTemplate来简化JDBC的使用,它会自动为应用获取正确的连接。
 

TransactionAwareDataSourceProxy

在最低层存在一个TransactionAwareDataSourceProxy类,它是DataSource的代理类,包装了DataSource,以添加Spring事务管理的感知功能,类似于由Java EE服务器提供的事务性JNDI DataSource。

除非现存代码必须通过传递一个标准的JDBC DataSource实现进行调用,否则这个类不应该被使用。

Spring框架事务支持模型的优势的更多相关文章

  1. 跟着刚哥学习Spring框架--事务配置(七)

    事务 事务用来保证数据的完整性和一致性. 事务应该具有4个属性:原子性.一致性.隔离性.持久性.这四个属性通常称为ACID特性.1.原子性(atomicity).一个事务是一个不可分割的工作单位,事务 ...

  2. spring对事务支持的三种形式

    spring对事务支持的三种形式: 1.通过spring配置文件进行切面配置 <bean id="***Manager" class="org.springfram ...

  3. Spring框架——事务管理方式搭建一个小的项目

    学习Spring框架,通过事务管理的方式搭建一个小的项目,该项目可以查询对数据库中的图书库存数量进行修改. 首先,使用MVC分层的设计模式思想搭建项目目录结构. 此部分代码源码之中都有相关注释,所以尽 ...

  4. spring框架 事务 注解配置方式

    user=LF password=LF jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl driverClass=oracle.jdbc.driver.Ora ...

  5. spring框架 事务 xml配置方式

    user=LF password=LF jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl driverClass=oracle.jdbc.driver.Ora ...

  6. Spring Boot事务支持

    一.创建项目 二.添加依赖 <dependencies> <dependency> <groupId>org.projectlombok</groupId&g ...

  7. spring boot 事务支持

  8. Spring 框架的事务管理

    1. Spring 框架的事务管理相关的类和API PlateformTransactionManager 接口: 平台事务管理器(真正管理事务的类); TransactionDefinition 接 ...

  9. IDEA02 利用Maven创建Web项目、为Web应用添加Spring框架支持、bean的创建于获取、利用注解配置Bean、自动装配Bean、MVC配置

    1 环境版本说明 Jdk : 1.8 Maven : 3.5 IDEA : 专业版 2017.2 2 环境准备 2.1 Maven安装及其配置 2.2 Tomcat安装及其配置 3 详细步骤 3.1 ...

随机推荐

  1. linux kernel 的配置及编译

    1. 执行make menuconfig 配置内核 2. 执行make zImage 编译内核 3. 执行make modules 编译模块 4. 内核源代码的配置及编译系统 Makefile Kco ...

  2. 关于Application.DoEvents()==转

    记得第一次使用Application.DoEvents()是为了在加载大量数据时能够有一个数据加载的提示,不至于系统出现假死的现象,当时也没有深入的去研究他的原理是怎样的,结果在很多地方都用上了App ...

  3. 84. Largest Rectangle in Histogram (Array, Stack; DP)

    Given n non-negative integers representing the histogram's bar height where the width of each bar is ...

  4. TIME_WAIT状态的作用

    TIME_WAIT状态: 主动关闭的那端最后经历的状态,一般为2MSL秒(1~4分钟). 两个原因: 保证当最后一个ack丢失后,能收到对端重传的fin包. 保证ack包消失,不会影响下一个连接. 关 ...

  5. 归并排序/合并排序c++实现

    #include <iostream>#include<string.h> using namespace std;class merges{public:void merge ...

  6. 【校招面试 之 剑指offer】第10-2题 青蛙跳台阶问题

    题目1:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个n级台阶共有多少种跳法? 题目2:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶...也可以一次跳n级台阶.求该青蛙跳上一个 ...

  7. C++ 模板的全特化与偏特化

    模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的. 模板分为类模板与函数模板,特化分为全特化与偏特化.全特化就是限定死模板实现的具体类型,偏特化就是如果这 ...

  8. 找不到reportviewer控件在哪儿

    請自行加入ReportViewer(9.0)到工具箱之中. 如下圖,

  9. Python 安装路径, dist-packages 和 site-packages 区别

    Stack Overflow's answer 译: dist-packages is a Debian-specific convention that is also present in its ...

  10. Spring整合Struts2框架的第一种方式(Action由Struts2框架来创建)。在我的上一篇博文中介绍的通过web工厂的方式获取servcie的方法因为太麻烦,所以开发的时候不会使用。

    1. spring整合struts的基本操作见我的上一篇博文:https://www.cnblogs.com/wyhluckdog/p/10140588.html,这里面将spring与struts2 ...