Spring框架事务支持模型的优势
全局事务
全局事务支持对多个事务性资源的操作,通常是关系型数据库和消息队列。应用服务器通过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框架事务支持模型的优势的更多相关文章
- 跟着刚哥学习Spring框架--事务配置(七)
事务 事务用来保证数据的完整性和一致性. 事务应该具有4个属性:原子性.一致性.隔离性.持久性.这四个属性通常称为ACID特性.1.原子性(atomicity).一个事务是一个不可分割的工作单位,事务 ...
- spring对事务支持的三种形式
spring对事务支持的三种形式: 1.通过spring配置文件进行切面配置 <bean id="***Manager" class="org.springfram ...
- Spring框架——事务管理方式搭建一个小的项目
学习Spring框架,通过事务管理的方式搭建一个小的项目,该项目可以查询对数据库中的图书库存数量进行修改. 首先,使用MVC分层的设计模式思想搭建项目目录结构. 此部分代码源码之中都有相关注释,所以尽 ...
- spring框架 事务 注解配置方式
user=LF password=LF jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl driverClass=oracle.jdbc.driver.Ora ...
- spring框架 事务 xml配置方式
user=LF password=LF jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl driverClass=oracle.jdbc.driver.Ora ...
- Spring Boot事务支持
一.创建项目 二.添加依赖 <dependencies> <dependency> <groupId>org.projectlombok</groupId&g ...
- spring boot 事务支持
- Spring 框架的事务管理
1. Spring 框架的事务管理相关的类和API PlateformTransactionManager 接口: 平台事务管理器(真正管理事务的类); TransactionDefinition 接 ...
- 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 ...
随机推荐
- linux kernel 的配置及编译
1. 执行make menuconfig 配置内核 2. 执行make zImage 编译内核 3. 执行make modules 编译模块 4. 内核源代码的配置及编译系统 Makefile Kco ...
- 关于Application.DoEvents()==转
记得第一次使用Application.DoEvents()是为了在加载大量数据时能够有一个数据加载的提示,不至于系统出现假死的现象,当时也没有深入的去研究他的原理是怎样的,结果在很多地方都用上了App ...
- 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 ...
- TIME_WAIT状态的作用
TIME_WAIT状态: 主动关闭的那端最后经历的状态,一般为2MSL秒(1~4分钟). 两个原因: 保证当最后一个ack丢失后,能收到对端重传的fin包. 保证ack包消失,不会影响下一个连接. 关 ...
- 归并排序/合并排序c++实现
#include <iostream>#include<string.h> using namespace std;class merges{public:void merge ...
- 【校招面试 之 剑指offer】第10-2题 青蛙跳台阶问题
题目1:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个n级台阶共有多少种跳法? 题目2:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶...也可以一次跳n级台阶.求该青蛙跳上一个 ...
- C++ 模板的全特化与偏特化
模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的. 模板分为类模板与函数模板,特化分为全特化与偏特化.全特化就是限定死模板实现的具体类型,偏特化就是如果这 ...
- 找不到reportviewer控件在哪儿
請自行加入ReportViewer(9.0)到工具箱之中. 如下圖,
- Python 安装路径, dist-packages 和 site-packages 区别
Stack Overflow's answer 译: dist-packages is a Debian-specific convention that is also present in its ...
- Spring整合Struts2框架的第一种方式(Action由Struts2框架来创建)。在我的上一篇博文中介绍的通过web工厂的方式获取servcie的方法因为太麻烦,所以开发的时候不会使用。
1. spring整合struts的基本操作见我的上一篇博文:https://www.cnblogs.com/wyhluckdog/p/10140588.html,这里面将spring与struts2 ...