spring 事务管理

Spring框架引人注目的重要因素之一是它全面的事务支持。Spring框架提供了一致的事务管理抽象,这带来了以下好处:
为复杂的事务API提供了一致的编程模型,如JTA、JDBC、Hibernate、JPA和JDO
支持 声明式事务管理
提供比大多数复杂的事务API(诸如JTA)更简单的,更易于使用的 编程式 事务管理API
非常好地整合Spring的各种数据访问抽象


传统上,J2EE开发者有两个事务管理的选择: 全局 或 本地 事务。
全局事务由应用服务器管理,使用JTA。
局部事务是和资源相关的,比如一个和JDBC连接关联的事务。这个选择有深刻的含义。
例如,全局事务可以用于多个事务性的资源(典型例子是关系数据库和消息队列)。
使用局部事务,应用服务器不需要参与事务管理,并且不能帮助确保跨越多个资源(需要指出的是多数应用使用单一事务性的资源)的事务的正确性。

全局事务有一个重大的缺陷,代码需要使用JTA:一个笨重的API(部分是因为它的异常模型)。此外,JTA的UserTransaction通常需要从JNDI获得,这意味着我们为了JTA,需要 同时 使用JNDI 和 JTA。
使用全局事务的首选方式是通过EJB的 CMT(容器管理事务):CMT是 声明式事务管理 的一种形式(区别于 编程式事务管理)。
重大的缺陷是CMT绑定在JTA和应用服务器环境上,并且只有我们选择使用EJB实现业务逻辑,或者至少处于一个事务化EJB的外观(Facade)后才能使用它。

本地事务. 本地事务容易使用,但也有明显的缺点:它们不能用于多个事务性资源。
例如,使用JDBC连接事务管理的代码不能用于全局的JTA事务中。
另一个缺点是局部事务趋向于入侵式的编程模型。
Spring解决了这些问题。它使应用开发者能够使用在 任何环境 下使用 一致 的编程模型.Spring框架同时提供声明式和编程式事务管理。声明事务管理是多数使用者的首选,在多数情况下是被推荐使用的。
如何解决??AOP?回调
使用编程式事务管理,开发者直接使用Spring框架事务抽象,这个抽象可以使用在任何底层事务基础之上。
使用首选的声明式模型,开发者通常书写很少的或没有与事务相关的代码,因此不依赖Spring框架或任何其他事务API。

Spring事务抽象的关键是事务策略的概念。这个概念由org.springframework.transaction.PlatformTransactionManager接口定义。
TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务。如同J2EE事务环境,一个 TransactionStatus 也是和执行 线程 绑定的)。
TransactionDefinition接口指定:
1、事务隔离:当前事务和其它事务的隔离的程度。例如,这个事务能否看到其他事务未提交的写数据?
2、事务传播:通常在一个事务中执行的所有代码都会在这个事务中运行。但是,如果一个事务上下文已经存在,有几个选项可以指定一个事务性方法的执行行为:例如,简单地在现有的事务中继续运行(大多数情况);或者挂起现有事务,创建一个新的事务。Spring提供EJB CMT中常见的事务传播选项。
3、事务超时: 事务在超时前能运行多久(自动被底层的事务基础设施回滚)。
4、只读状态: 只读事务不修改任何数据。只读事务在某些情况下(例如当使用Hibernate时),是一种非常有用的优化。
这些设置反映了标准概念。

事务的四个特性:原子、一致、隔离、持久。

TransactionStatus 接口为处理事务的代码提供一个简单的控制事务执行和查询事务状态的方法。

使用Spring时,无论你选择编程式还是声明式的事务管理,定义一个正确的 PlatformTransactionManager 实现都是至关重要的。
按照Spring的良好风格,这种重要定义都是通过IoC实现的。

一般来说,选择PlatformTransactionManager实现时需要知道当前的工作环境,如JDBC、JTA、Hibernate等。

局部事务:我们需要定义一个Hibernate的 LocalSessionFactoryBean,应用程序从中获取到Hibernate Session 实例。

如果是一个JEE容器提供的 DataSource,它将由JEE容器自身,而不是Spring框架来管理事务。????
这种情况中'txManager' bean的类型为 HibernateTransactionManager。同样地,DataSourceTransactionManager 需要一个指向 DataSource 的引用,而 HibernateTransactionManager 需要一个指向 SessionFactory 的引用。
JEE容器提供的 DataSource????全局事务确认。全局事务,可以支持任何事务性资源。

现在应该比较清楚的是:不同的事务管理器是如何创建的,以及它们如何被连接到相应的需要被同步到事务的资源上。
剩下的问题是:直接或间接地使用一种持久化API(JDBC、Hibernate、JDO等)的应用代码,如何确保通过相关的 PlatformTransactionManager 来恰当地获取并操作资源,来满足事务同步,这些操作包括:创建、复用、清理 和 触发(可能没有)。
高层次方案:
首选的方法是使用Spring的高层持久化集成API。对所有持久化API都采用这种 模板 方法,包括 JdbcTemplate、HibernateTemplate和JdoTemplate类.
低层次方案
在较低层次上,有以下这些类:DataSourceUtils(针对JDBC),SessionFactoryUtils(针对Hibernate),PersistenceManagerFactoryUtils(针对JDO)等等。
当对应用代码来说,直接同原始持久化API特有的资源类型打交道是更好的选择时,这些类确保应用代码获取到正确的Spring框架所管理的bean,事务被正确同步,处理过程中的异常被映射到一致的API。
保证了跨数据库——甚至其他持久化技术——的移植性。
这些类同样可以在没有Spring事务管理的环境中工作良好(事务同步能力是可选的),所以无论你是否使用Spring的事务管理,你都可以使用这些类。

DataAccessExceptions好处?

声明式事务管理:
最符合 非侵入式 轻量级容器的理念。
Spring的声明式事务管理是通过Spring AOP实现的。
因为事务方面的代码与Spring绑定并以一种样板式风格使用, 不过尽管如此,你一般并不需要理解AOP概念就可以有效地使用Spirng的声明式事务管理。

EJB CMT和Spring声明式事务管理的相似以及不同之处出发是很有益的。重要

回滚规则的概念比较重要:它使我们能够指定什么样的异常(和throwable)将导致自动回滚。
我们在配置文件中声明式地指定,无须在Java代码中。
我们仍旧可以通过调用 TransactionStatus 的 setRollbackOnly() 方法编程式地回滚当前事务。

默认式Spring处理声明式事务管理的规则遵守EJB习惯(只在遇到unchecked exceptions时自动回滚),但通常定制这条规则会更有用。

Spring的事务管理是通过AOP代理实现的。
其中的事务通知由元数据(目前基于XML或注解)驱动。
代理对象与事务元数据结合产生了一个AOP代理,它使用一个PlatformTransactionManager 实现品配合TransactionInterceptor,在方法调用前后实施事务。

推荐做法是在Spring框架的事务架构里指出当context的事务里的代码抛出 Exception 时事务进行回滚。
Spring框架的事务基础架构代码将从调用的堆栈里捕获到任何未处理的 Exception,并将标识事务将回滚。

注意Spring框架的事务基础架构代码将默认地 只 在抛出运行时和unchecked exceptions时才标识事务回滚。
也就是说,当抛出一个 RuntimeException 或其子类例的实例时才会回滚。从事务方法中抛出的Checked exceptions将 不 被标识进行事务回滚。

第一种方法可以配置哪些 Exception类型将被标识进行事务回滚。 no-rollback-for rollback-for
第二种方法是通过 编程式 方式来指定回滚事务。


假设你有许多服务对象,你想为他们分别设置 完全不同 的事务语义。
在Spring中,你可以通过分别定义特定的 <aop:advisor/> 元素, 让每个advisor采用不同的 'pointcut' 和 'advice-ref' 属性,来达到目的。

两个拥有完全不同的事务配置的bean。

默认的 <tx:advice/> 设置如下:
事务传播设置 是 REQUIRED
隔离级别是DEFAULT
事务是 读/写
事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚

除了基于XML文件的声明式事务配置外,你也可以采用基于注解式的事务配置方法。Java 5(Tiger)。

一般配置都有个默认的问题:如果你用 'transactionManager' 来定义 PlatformTransactionManager bean的名字的话,你就可以忽略 <tx:annotation-driven/> 标签里的 'transaction-manager' 属性。 如果 PlatformTransactionManager bean你要通过其它名称来注入的话,你必须用 'transaction-manager' 属性来指定它。

请注意只是使用 @Transactional 注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。
<tx:annotation-driven/>元素的出现 开启 了事务行为。

Spring团队的建议是你只在具体的类上使用 @Transactional 注解, 而不要注解在接口上。
你当然可以在接口(或接口方法)上使用 @Transactional 注解, 但是这只有在你使用基于接口的代理时它才会生效。
因为注解是 不能继承 的, 这就意味着如果你正在使用基于类的代理时,事务的设置将不能被基于类的代理所识别,而且对象也不会被事务代理所包装 (这是很糟糕的)。

‘自我调用’是不会触发事务的,比如说,一个在目标对象中调用目标对象其他方法的方法是不会触发一个事务的,即使这个方法被标记为 @Transactional!

在多数情形下,方法的事务设置将被优先执行。

在由Spring管理的事务中,请记住 物理 和 逻辑 事务存在的差异, 以及传播设置是如何影响到这些差异的。

获得到一个拥有剖析和事务方面的 。

Spring提供两种方式的编程式事务管理:
1、使用 TransactionTemplate
2、直接使用一个 PlatformTransactionManager 实现
如果你选择编程式事务管理,Spring小组推荐使用 TransactionTemplate。 第二种方法则类似使用JTA的 UserTransaction API

TransactionTemplate 它使用回调机制,将应用代码从样板式的资源获取和释放代码中解放出来, 这样写出的代码是目的驱动的,把精力集中在开发者想要做的事情上。
使用 TransactionTemplate 绝对会增加你的代码与Spring的事务框架和API间的耦合。

写一个 TransactionCallback 的实现, (通常会用匿名类来实现 )这样的实现会包含所以你需要在该事务上下文中执行的代码。
然后把一个实现TransactionCallback的实例传递给TransactionTemplate暴露的execute(..) 方法。
return transactionTemplate.execute(new TransactionCallback() {
// the code in this method executes in a transactional context
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
如果不需要返回值,更方便的方式是创建一个 TransactionCallbackWithoutResult 的匿名类,如下:
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});
回调方法内的代码可以通过调用 TransactionStatus 对象的 setRollbackOnly() 方法来回滚事务。

诸如传播模式、隔离等级、超时等等的事务设置都可以在TransactionTemplate中或者通过配置或者编程式地实现。 TransactionTemplate实例默认继承了默认事务设置。

TransactionTemplate 类的实例是线程安全的,任何状态都不会被保存。

可以使用 org.springframework.transaction.PlatformTransactionManager 来直接管理你的事务。
只需通过bean的引用,简单的把你在使用的PlatformTransactionManager 传递给你的bean。
然后,使用TransactionDefinition和TransactionStatus对象, 你可以启动,回滚和提交事务。

只有编程式事务管理才能显式的设置事务名称。

你可能感兴趣的:(spring,AOP,编程,Hibernate,配置管理)