现在的位置: 首页 > 综合 > 正文

Spring in Action 学习笔记—第五章 事务管理

2013年08月28日 ⁄ 综合 ⁄ 共 3579字 ⁄ 字号 评论关闭

Spring in Action 学习笔记第五章 事务管理

 

本章是第四章的延续,作者向读者展示了如何使用Spring事务管理来保证数据一致性。Spring对事务的管理有丰富的支持,程序控制的和声明式的都有。在本章中,我们会学习到如何把应用程序的代码放置在事务中,以确保在一切顺利时,所有的成果都被固定下来;一旦其中有一步出错,那么整个事情就像没有发生一样。

 

一、理解事务

首先我们应该弄清楚什么是事务,这样才能认识到事务的重要性。举一个小小的例子,大概每个人都有转账的经历。当我们从A帐户向B帐户转100元后,银行的系统会从A帐户上扣除100而在B帐户上加100,这是一般的正常现象。但是一旦系统出错了怎么办呢,这里我们假设可能会发生两种情况:(1A帐户上少了100元,但是B帐户却没有多100元。(2B帐户多了100元钱,但是A帐户上却没有被扣钱。这种错误一旦发生就等于出了大事,那么再假如一下,你要转账的是1亿呢?所以上面的两种情况分别是你和银行不愿意看到的,因为谁都不希望出错。那么有没有什么方法保证一旦A帐户上没有被扣钱而B帐户上也没有被加钱;或者A帐户扣了100元而B帐户准确无误的加上100元呢。也就是说要么转账顺利的成功进行,要么不转账呢?可以,这就是数据库事务机制所要起到的作用和做的事情。

下面给出事务的概念(在数据库中事务的概念在表述上略有差异,但是含义都是一样的):

所谓事务是用户定义的一个数据库操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。事务具有四个特性:

1.         原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列。这些操作要么完整的被全部执行,要么一步也不做。是一个逻辑工作单位。

2.         一致性:一个事务独立执行的结果将保持一致性,即数据不会因为事务的执行而遭受破坏。

3.         隔离性:一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

4.         持久性:一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其执行结果有任何影响。

结合前面的例子解释一下概念:在转账示例中A100元钱和B100元钱这两步更新操作就是一个操作序列。这两步是一个整体要么全部成功,要么全部成功,绝对不能只成功一步而另一步失败。关于数据库事务的详细知识请参考有关的数据库原理书籍。

Spring框架引人注目的重要因素之一是它全面的事务支持。Spring支持编程式事务声明式事务

 

二、在Spring中编写事务

在我们的代码中添加事务的一种方法就是使用SpringTransactionTemplate类,用程序添加事务边界。就像其他Spring的模版类一样,TransactionTemplate利用一套回调机制,把我们的代码包装在一个TransactionTemplate里。看下面的代码片断:

       public void enrollStudentInCourse()

       {

              tran.execute(new TransactionCallback()

              {

                     public Object doInTransaction(TransactionStatus ts){

                            try{

                                   //do something....

                            }catch(Exception ex){

                                   ts.setRollbackOnly();//出错进行事务回滚

                            }

                            return null;

                     }

              }

              );

       }

下面是配置文件:

<bean id = "transactionTemplate" class = "org.springframework.transaction.support.TransactionTemplate">

       <property name="transactionManager"><ref bean = "transactionTemplate"/></property>

</bean>

 

<bean id = "courseService" class = "MyImp">

       <property name="transactionTemplate"><ref bean = "transactionTemplate"/></property>

</bean>

transactionTemplate对象有一个transactionManager属性。该属性为PlatformTransactionManager类型,它用来处理特定平台的事务管理的细节。也可以直接使用 org.springframework.transaction.PlatformTransactionManager的实现来管理事务。只需通过bean引用简单地传入一个 PlatformTransactionManager 实现,然后使用 TransactionDefinition TransactionStatus 对象,你就可以启动一个事务,提交或回滚。在上例的简单代码中我们展示的是编程式事务当你完全希望控制事务的边界时候,编程式事务是不错的。但是他有些侵入性。通常我们的事务需求并没有要求在事务的边界上进行如此精确的控制。我们可以使用声明式事务

 

三、声明式事务

大多数Spring用户选择声明式事务管理。这是对应用代码影响最小的选择,因此也最符合 非侵入式 轻量级容器的理念。Spring的声明式事务管理是通过Spring AOP实现的,因为事务方面的代码与Spring绑定并以一种样板式风格使用,这样做是非常自然的,因为事务时系统级的,凌驾于应用的主要功能之上的,你可以把Spring的事务想象成是一个切面(方面)包裹着一个方法。不过尽管如此,你一般并不需要理解AOP概念就可以有效地使用Spirng的声明式事务管理。

Spring2.0之前要在Spring中使用声明式事务,得用TransactionProxyFactoryBean。这是一个接口,他有点类似在第三章中的ProxyFactoryBean,只不过它的目的是将方法包装在事务的上下文中。Spring2.0及以后的版本中声明式事务的配置与之前的版本有相当大的不同。主要差异在于不再需要配置TransactionProxyFactoryBean了。Spring2.0之前的旧版本风格的配置仍然是有效的;你可以简单地认为新的<tx:tags/>替你定义了TransactionProxyFactoryBean。和TransactionProxyFactoryBean配合的还有两个,一个是PlatformTransactionManager另一个是TransactionAttributeSource

1.理解事务属性:

Spring里,事务属性是对事务策略如何应用到方法的描述。这个描述包括下列一些参数:传播行为、隔离级别、只读提示、事务超时间隔。

(1)传播行为

传播行为定义了关于客户端和被调用方法的事务边界。Spring定义了7种截然不同的传播行为。(在书中165页有详细列表)Spring的传播行为分别对应了EJB容器管理的事务(CMT)中所有的传播规则。传播规则回答了一个问题,就是新的事务是否要被启动或是被挂起,或者方法是否要在事务环境中运行。

2)隔离级别

在一个典型的应用中,多个事务并发运行,经常会操作同一个数据来完成任务。并发会导致以下问题:

l         脏读——脏读发生在一个事务读取了被另一个事务改写但还未提交的数据时。

l         不可重复读——不可重复读发生在一个事务执行相同的查询两次或两次以上,但每一次查询结果不同时。

l         幻读——幻读和不可重复读相似。

在理想状态下,事务要完全相互隔离,以防止这些问题发生。(这些内容在数据库原理里面都有讲解,大家可以参考数据库原理的相关书)然而完全隔离会影响性能,因为隔离经常牵扯到锁定在数据库中的记录。侵占性的锁定会阻碍并发,要求事务相互等待来完成工作,这样会引起

抱歉!评论已关闭.