5事务管理
为了描述事务的概念,我们拿买电影票来举例。买一张电影票通常有一下步骤:
检查剩余座位的数量,确定是否能给你提供你需要的座位个数
每卖出一张票,可用座位的数量就应该减一
付款
售票员把票给你
如果一切顺利的话,你就可以欣赏到一场一鸣惊人的电影,而影院也增加了收入。但是如果有环节出差错了怎么办呢?比如说:你用来付款的信用卡没钱了?显然,你不会拿到票,影院也拿不到钱。但是如果说座位的数量在下个人购买之前没有被恢复到原来的状态,那么电影也许因为人为原因而不会满场了。或者如果出现这样的情况:一切都很顺利,但是发放票的时候出了问题。你只好乖乖的呆在家里看电视了,而且还损失了一小笔钱。
为了保证剧院和你都不受到损失,上面的操作应该用事务封装起来。作为事务,它应该被看成是一个单独的动作,以保证要么所有的操作都成功,或者所有的操作都回滚到初始的状态。
在软件中,事务有着举足轻重的地位,确保数据和资源保持一致的状态。如果没有事务,那么数据有可能因为应用程序的业务逻辑而变成脏数据,或者变成与其他数据不统一的数据。
让我们快速浏览一下事务向导和他是如何工作的。有以下四个因素。
5.1.1 用四句话来解释事务
在软件开发的一个重要传统里,可以用一个单词首字母的缩写来描述一个事务:ACID,简言之,ACID代表
Atomic(原子性)事务由一个或多个动作绑定起来作为一个单独的工作单元。原子性保证事务中所有的操作要么都执行,或者都不执行。如果所有的动作都执行了,那么事务就是成功的,如果其中有一个动作失败了,那么整个事务都失败,而且要执行回滚操作。
Consistent(一致性)一旦事务结束(可能成功了也可能失败了),那么系统所模拟的业务逻辑要处于一致的状态。数据不应该被实体关系破坏。
Isolated(隔离性)事务应该允许多个用户操作一个数据,一个用户的操作应该不受另一个
用户操作的影响。因此事务之间应该是相互隔离的,以阻止他们在操作中同时读写同一数据。(一般是以乐观锁来实现这一特性的)
Durable(持久性)一旦事务完成,事务执行的结果就应该被保存到数据库中,这样即使因为某一原因系统崩了,数据还能保存下来。传统上是把结果保存到数据库或者其他某种格式的持久化介质中。
在刚才的电影票的例子中,如果任何一个步骤失败的话事务可以所有取消操作的结果来保证原子性。原子性可以通过保证系统的数据从来没有不一致的状态,和从来没有部分执行的状况来保证一致性。隔离性可以通过阻止其他并发事务在你正在购买你的座位的时候把这个座位从你那里偷走来保证一致性。
最终的效果就是持久性,因为它们已经被保存到存储介质中去了。如果系统崩了或有其他类似的事件发生的话你也不需要担心事务的结果会丢失。
如果需要更详细的解释,我们建议你看看Martin Fowler写的Patterns of Enterprise Application Architecture。尤其是第五章,讨论了并发和事务。
5.1.2 理解spring对事务处理的支持
ejb一样,spring也提供了对包括的两种事务的支持,但是spring的事务管理能力超过了ejb的事务管理能力。
Spring对代码级事务管理的支持很大程度上不同于ejb。与ejb不同的是,ejbjta实现是联系在一起的,spring使用的是一种招回机制以从从事务代码种抽象出真实的事务实现。事实上,spring的事务管理甚至不需要一个jta的实现。如果你的应用程序只使用一个单一的持久资源,那么你就可以使用持久机制提供的事务支持来处理你的事务。这包括jdbchibernatejdoojb。然而,如果你的程序有涉及到多个资源的事务需求,spring可以用第三方的jta实现来提供一个分布式的事务支持。在5.2种我们将讨论spring对代码级事务管理的支持。
在你的代码中,代码级事务管理提供给你精确的弹性来定义的事务边界,声明式事务在其事务规则中帮助你减弱了操作带来的影响。Spring对声明式事务处理的支持让我们想起了ejb的容器管理事务(spring roll怎么读cmt)。两者都允许你们显式的定义事务的边界。但是spring的声明式事务超出了cmt,因为它允许你声明附加的属性,比如说隔离级别和timeouts。在5.3中我们将阐述spring的声明式事务管理。
选择代码级事务管理还是声明式事务管理就决定了你是选择了对程序(fine-grained)严密的控制还是选择了方便。当你把事务编写到你的代码中时,你就可以精确的控制事务的边界,在你需要的地方精确的开始和结束事务。一般的做法是,你不需要代码级提供的对程序的精密的控制时就选择把你的事务声明到一个上下文环境中去(就是说选择声明式事务管理)。
不管你是否选择把事务写到你的bean中还是当作一个切面来声明它们,你将使用一个spring的事务管理来作为接口插入到平台具体的事务实现中。让我们看一下spring的事务管理是如何用平台的具体的事务实现把你从事务处理中解放出来的。
5.1.3 介绍spring的事务管理
Spring并没有直接管理事务,取而代之的是,它提供了另一个选择,把事务管理部分的责任委托给平台具体的事务实现,这些事务实现可能是jta提供的或者也可以是持久机制提供的。
这里我们将着重介绍springhibernate的事务支持。
Hibernate的事务
如果你的程序是用hibernate来实现持久化的,那么你要使用HibernateTransactionManager这个类。用下面提供的xml文件来在程序中声明这个类。




sesssionFactory这个property应该填上一个hibernateSessionFactory,这里最好取名为sessionFactory。上面有如何创建一个hibernateSessionFactory的详细的讲解。
HibernateTransactionManager把事务管理的责任委托给一个net.sf.hibernate.Transaction对象,这个对象可以hibernatesession对象得到。类似的,当一个事务失败了,事务对象就会调用rollback()这个方法执行回滚操作。
5.2spring中开发事务处理程序
CourseService类的enrollStudentInCourse()方法在一个学生注册一门课程的过程中要执行多
个步骤,如果其中的任何一个步骤出错,那么所有的操作都必须回滚到改方法执行前的状态。换句话说,enrollStudentInCourse()方法必须要用事务包装起来。
把事务加到你的代码中的途径之一就是利用springTransactionTemplate类把事务边界以代码的形式写到程序中。就像spring中的其他模板类一样,TransactionTemplate使用了一个招回机制。下面的代码告诉你怎么用TransactionTemplate来包装你的代码。
Public void enrollStudentInCourse(){
ute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus ts){
try{
//do stuff <-Runs within doInTransaction()
}catch(Exceptin e){
Ts.setRollbackOnly(); <-Calls setRollbackOnly() to roll back
}
Return null ; <-if successful transaction is committed
}
});
}
你以实现TransactionCallback接口为开始。因为TransactionCallback只需要实现一个方法,作为一个匿名内部类来说实现这个方法通常是最简单的。把这些代码放在doInTransaction()方法中的上下文事务环境中,再把这个doInTransaciton方法放在你的程序要执行上面这些代码的地方(不理解就看上面这段代码是怎么做的)。
TransactionTemplate实例中使用execute()方法将执行包含在TransactionCallback实例中的代码。如果你的代码遇到问题,那么调用TransactionStatus对象的setRollbackOnly() 方法将回滚事务。否则,如果doInTransaction()方法成功返回的话,事务将会被提交。
TransactionTemplate实例是怎么得到的呢?这是一个不错的疑问,它应该被注入到CourseServiceImpl类中,像下面那样:








注意一下,transactionTemplate这个bean有一个transactionManagerproperty(属性)。隐藏在表象之下的是,TransactionTemplate使用了一个PlatformTransactionManager(这是一个接口)的实现来处理平台具体的事务管理的细节。这里我们注册了一个名为transactionManagerbean的引用,这个bean可以是任意一种PlatformTransactionManager接口的实现(比如说DataSourceTransactionManager,HibernateTransactionManager,JdoTransactionManager,JtaTransactionManager,或者是PersistenceBrokerTransactionManager)。
当你需要完全控制事务边界的时候代码级事务管理是很好的。但是,正如你上面所看到的,
这样做有点烦,你不得不更改enrollStudentInCourse()方法的实现,为了得到spring的代码级事务的支持你不得不使用spring的具体的类。
通常你的事务需求不需要那么精密的控制事务边界。那就是为什么一般你选择在程序外面声明你的事务的原因了(比如说在spring的配置文件中)。下面我们将要讲解spring的声明式事务管理。
5.3 声明事务
在不久之前,声明式事务管理只有在ejb容器中才能实现。但是现在spring也提供了对pojo的声明式事务管理的支持。这是一个spring的一个意义重大的特性,因为你的应用程序不再只是因为要得到声明式原子性操作而需要复杂而且重量级的ejb了。
Spring对声明式事务的支持实际上是springaop框架的一个实现。Aop显然很适合来实现声明式事务管理,因为事务是系统级的服务,应该是在应用程序主功能的上面一层。你可以把spring的事务认作是包装了一个方法的切面。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。