资源描述
第十八章第十八章SpringSpring事务管理事务管理课程目标课程目标 SpringSpring事务管理的概念事务管理的概念 SpringSpring事务抽象事务抽象 SpringSpring事务策略事务策略 SpringSpring提供的事务管理提供的事务管理 使用使用SpringSpring编程式的事务处理编程式的事务处理 使用使用SpringSpring声明式的事务处理声明式的事务处理体验项目体验项目Spring 程序实现的功能:程序实现的功能:该程序实现了该程序实现了Spring与与JDBC的结合,并在的结合,并在xml配置文件 中采用了参数化配置的事务管理。程序实现向数据库中添加一 条数据的功能。程序中,配置文件 中采用了参数化配置的事务管理。程序实现向数据库中添加一 条数据的功能。程序中,JdbcTemplate封装了事务管理的功 能,包括异常时的事务回滚,以及操作成功后的事务提交,它 使得我们无需在琐碎的封装了事务管理的功 能,包括异常时的事务回滚,以及操作成功后的事务提交,它 使得我们无需在琐碎的try/catch/finally代码中徘徊。代码中徘徊。运行的结果:运行的结果:该程序由于没有设计关于界面的操作,所以无法提供程序 运行的操作步骤。当程序运行之后,会将该程序由于没有设计关于界面的操作,所以无法提供程序 运行的操作步骤。当程序运行之后,会将“lily”的信息添加至数 据库中。详细过程请参考本章的信息添加至数 据库中。详细过程请参考本章“实践实践”部分。部分。SpringSpring事务管理的概念事务管理的概念有这么一句话来形容有这么一句话来形容Spring:“对数据持久层的杰出贡献,可能是对数据持久层的杰出贡献,可能是Spring 最为闪亮的优点。最为闪亮的优点。”然而与数据持久层息息相关的正是数据库的事务管理。对 于然而与数据持久层息息相关的正是数据库的事务管理。对 于J2EE应用程序而言,事务的处理一般有两种模式:依赖特定事务资源的事务处理这种事务处理的模式是应用开发中最常见的,通过特定资源提供的事务 处理机制进行事务管理。如:通过应用程序而言,事务的处理一般有两种模式:依赖特定事务资源的事务处理这种事务处理的模式是应用开发中最常见的,通过特定资源提供的事务 处理机制进行事务管理。如:通过JDBC、JTA的的commit()方法和方法和roolback()方法,方法,Hibernate Transaction的的commit()方法和方法和roolback()方法等。依赖容器的参数化事务管理方法等。依赖容器的参数化事务管理EJB的事务管理模式就是通过容器提供的集约式参数化事务机制,实现 事务的外部管理。容器管理的参数化事务为程序的开发提供了相当的灵活 性,同时因为将事务委托给容器进行管理,应用逻辑中就无需编辑事务代 码,大大节省了代码量,从而提高了应用开发的效率。的事务管理模式就是通过容器提供的集约式参数化事务机制,实现 事务的外部管理。容器管理的参数化事务为程序的开发提供了相当的灵活 性,同时因为将事务委托给容器进行管理,应用逻辑中就无需编辑事务代 码,大大节省了代码量,从而提高了应用开发的效率。Spring 的事务管理机制与的事务管理机制与EJB 中事务管理有何区别?(中事务管理有何区别?(1)Spring可以将任意可以将任意Java Class 纳入事务管理。这里的纳入事务管理。这里的UserDAO只是 我们编写的一个普通只是 我们编写的一个普通Java Class,其中包含了一些基本的数据应用逻辑。通 过,其中包含了一些基本的数据应用逻辑。通 过Spring,我们即可简单的实现事务的可配置化。也就是说,我们可以随意 为某个类的某个方法指定事务管理机制。与之对比,如果使用,我们即可简单的实现事务的可配置化。也就是说,我们可以随意 为某个类的某个方法指定事务管理机制。与之对比,如果使用EJB容器提供 的事务管理功能,我们不得不按照容器提供 的事务管理功能,我们不得不按照EJB规范编程将规范编程将UserDAO进行改造,将其 转换为一个标准的进行改造,将其 转换为一个标准的EJB。(。(2)Spring的事务管理并不依赖特定的事务资源。的事务管理并不依赖特定的事务资源。EJB容器必须依赖于 容器必须依赖于 JTA 提供事务支持。而提供事务支持。而Spring的事务管理则支持的事务管理则支持JDBC、JTA 等多种事务资 源。这为我们提供了更多的选择,从而也使得我们的系统部署更加灵活。等多种事务资 源。这为我们提供了更多的选择,从而也使得我们的系统部署更加灵活。为不同的事务为不同的事务API提供一致的编程模型,如提供一致的编程模型,如JTA、JDBC、Hibernate、iBATIS数据库层和数据库层和JDO。提供比大多数事务提供比大多数事务API更简单的,易于使用的编程式事务管理更简单的,易于使用的编程式事务管理API。整合整合Spring数据访问抽象。支持数据访问抽象。支持Spring声明式事务管理。声明式事务管理。Spring 事务抽象事务抽象Spring提供了一致的事务管理抽象。这个抽象是提供了一致的事务管理抽象。这个抽象是Spring最重要的抽象之 一,它有如下的优点:局部事务是和资源相关的:例如,一个和最重要的抽象之 一,它有如下的优点:局部事务是和资源相关的:例如,一个和JDBC连接关联的事务。全局 事务可以用于多个事务性的资源。使用局部事务,应用服务器不需要参与事 务管理,并且不能帮助确保跨越多个资源的事务的正确性。全局事务有一个显著的不利方面,代码需要使用连接关联的事务。全局 事务可以用于多个事务性的资源。使用局部事务,应用服务器不需要参与事 务管理,并且不能帮助确保跨越多个资源的事务的正确性。全局事务有一个显著的不利方面,代码需要使用JTA:一个笨重的:一个笨重的API。此外,。此外,JTA的的UserTransaction通常需要从通常需要从JNDI获得,这意味着为了获得,这意味着为了JTA,需 要同时使用,需 要同时使用JNDI和和JTA。显然全部使用全局事务限制了应用代码的重用 性,因为。显然全部使用全局事务限制了应用代码的重用 性,因为JTA通常只在应用服务器的环境中才能使用。通常只在应用服务器的环境中才能使用。SpringSpring事务策略事务策略Spring事务抽象的关键是事务策略的概念。这个概念由事务抽象的关键是事务策略的概念。这个概念由org.springframework.transaction.PlatformTransactionManager接口体现,参考代码如下:接口体现,参考代码如下:public interface PlatformTransactionManagerTransactionStatus getTransaction(TransactionDefinition definition)throws TransactionException;void commit(TransactionStatus status)throws TransactionException;void rollback(TransactionStatus status)throws TransactionException;这首先是一个这首先是一个SPI接口,虽然它也可以在编码中使用。注意按照接口,虽然它也可以在编码中使用。注意按照Spring的 哲学,这是一个接口。因而如果需要它可以很容易地被模拟和桩化。它也没 有和一个查找策略如的 哲学,这是一个接口。因而如果需要它可以很容易地被模拟和桩化。它也没 有和一个查找策略如JNDI捆绑在一起:捆绑在一起:PlatformTransactionManager的实现 定义和其它的实现 定义和其它Spring IoC容器中的对象一样。这个好处使得即使使用容器中的对象一样。这个好处使得即使使用JTA,也 是一个很有价值的抽象:事务代码可以比直接使用,也 是一个很有价值的抽象:事务代码可以比直接使用JTA更加容易测试。更加容易测试。如同J2EE事务上下文一样,一个TransactionStatus也是和执行的线程相 关联的。TransactionDefinition接口指定:事务隔离:当前事务和其它事务的隔离程度。例如,这个事务能否 看到其它事务未提交的写数据。事务传播:通常在一个事务中执行的所有代码都会在这个事务中运 行。但是,如果一个事务上下文已经存在,有几个选项可以指定一个 事务性方法的执行行为:例如,简单地在现有的事务中运行(大多数 情况);或者挂起现有事务,创建一个新的事务。Spring提供EJB CMT中熟悉的事务传播选项。事务超时:事务在超时前能运行多久(自动被底层的事务基础设施 回滚)。只读状态:只读事务不修改任何数据。只读事务在某些情况下(例 如当使用Hibernate时)可以是一种非常有用的优化。使用使用Hibernate和和JTA事务,我们可以简单地使用事务,我们可以简单地使用JtaTransactionManager,就象,就象JDBC或任何其它资源策略一样。或任何其它资源策略一样。注意任何资源的注意任何资源的JTA配置都是这样的,因为它们都是全局事务。在 所有这些情况下,应用程序代码不需要任何更改。我们可以仅仅更改配 置来更改管理事务的方式,即使这些更改意味着从局部事务转换到全局 事务或者相反的转换。如果不使用全局事务,需要采用一个特定的编码规范。需要以一个 特殊的方式获得连接资源或者会话资源,允许相关的配置都是这样的,因为它们都是全局事务。在 所有这些情况下,应用程序代码不需要任何更改。我们可以仅仅更改配 置来更改管理事务的方式,即使这些更改意味着从局部事务转换到全局 事务或者相反的转换。如果不使用全局事务,需要采用一个特定的编码规范。需要以一个 特殊的方式获得连接资源或者会话资源,允许相关的PlatformTransactionManager实现跟踪连接的使用,并且当需要时应用事务管理。例如,如果使用实现跟踪连接的使用,并且当需要时应用事务管理。例如,如果使用JDBC,不应该调用一个数据源的,不应该调用一个数据源的getConnection()方 法,而必须使用方 法,而必须使用Spring的的 org.springframework.jdbc.datasource.DataSourceUtils类,参考代码如下:类,参考代码如下:Connection conn=DataSourceUtils.getConnection(dataSource);SpringSpring提供的事务管理提供的事务管理Spring提供的事务管理可以分为两类:编程式和声明式。编程式显得比较灵活,但是代码量大,存在代码重复的问题;声明式比编程式更加灵活,它是通过提供的事务管理可以分为两类:编程式和声明式。编程式显得比较灵活,但是代码量大,存在代码重复的问题;声明式比编程式更加灵活,它是通过Spring AOP实现的,所 以大多数的用户选择声明式事务管理。实现的,所 以大多数的用户选择声明式事务管理。以往使用以往使用JDBC进行数据操作时,使用进行数据操作时,使用DataSource从数据源中得到 从数据源中得到 Connection,我们知道数据源是线程安全的,而连接不是线程安全的,所以 对每个请求都是从数据源中重新取出一个连接。一般的数据源由容器进行管 理,包括连接池。例如,我们知道数据源是线程安全的,而连接不是线程安全的,所以 对每个请求都是从数据源中重新取出一个连接。一般的数据源由容器进行管 理,包括连接池。例如TOMCAT,WEBSPHERE,WEBLOGIC等这些 等这些 J2EE商业容器都提供了这个功能。商业容器都提供了这个功能。传统的传统的JDBC事务处理事务处理try conn=DBConnectionFactory.getConnection;conn.setAutoCommit(false);mit();catch(Exception e)conn.rollback();finally try conn.close();catch(SQLException se)Spring提供了两个关于事务处理的类:提供了两个关于事务处理的类:Spring编程式的事务处理编程式的事务处理 TransactionDefinition类,用于事务属性定义。类,用于事务属性定义。TranscationStatus类,代表当前的事务,可以提交和回滚事务。类,代表当前的事务,可以提交和回滚事务。PlatformTransactionManager这个是这个是Spring提供的用于管理事务的基础 接口,其下有一个实现的抽象类提供的用于管理事务的基础 接口,其下有一个实现的抽象类AbstractPlatformTransactionManager,我 们使用的事务管理类例如,我 们使用的事务管理类例如DataSourceTransactionManager等都是这个类的子 类。等都是这个类的子 类。使用编程式的事务管理流程如下:(使用编程式的事务管理流程如下:(1)声明数据源。()声明数据源。(2)声明一个事务管理类,例如:)声明一个事务管理类,例如:DataSourceTransactionManager,HibernateTransactionManger,JTATransactionManager等。(等。(3)在代码中加入事务处理代码:)在代码中加入事务处理代码:TransactionDefinition td=new TransactionDefinition();TransactionStatus ts=transactionManager.getTransaction(td);try/do something transactionMmit(ts);catch(Exception e)transactionManager.rollback(ts);使用使用spring提供的事务模板提供的事务模板TransactionTemplate:void add()transactionTemplate.execute(new TransactionCallback()pulic Object doInTransaction(TransactionStatus ts)/do something TransactionTemplate也是为我们省去了部分事务提交、回滚代码;定义事务模板时,需注入事务管理对象。也是为我们省去了部分事务提交、回滚代码;定义事务模板时,需注入事务管理对象。Spring声明式事务处理主要使用了声明式事务处理主要使用了IOC,AOP思想,提供了思想,提供了TransactionInterceptor拦截器和常用的代理类拦截器和常用的代理类TransactionProxyFactoryBean,可以直接 对组件进行事务代理。,可以直接 对组件进行事务代理。Spring提供的声明式的事务处理,是最少影响应用代 码的,因而这是和非侵入性的轻量级容器的观念是一致的。提供的声明式的事务处理,是最少影响应用代 码的,因而这是和非侵入性的轻量级容器的观念是一致的。Spring声明式事务处理(声明式事务处理(1)定义数据源,事务管理类。()定义数据源,事务管理类。(2)定义事务拦截器。使用)定义事务拦截器。使用TransactionInterceptor拦截器来实现事务处理的步骤如下:拦截器来实现事务处理的步骤如下:com.test.UserManager.*r=PROPAGATION_REQUIRED定义事务拦截器,参考代码如下:定义事务拦截器,参考代码如下:com.test.UserManager(3)为组件声明一个代理类:)为组件声明一个代理类:ProxyFactoryBean。PROPAGATION_REQUIREDPROPAGATION_REQUIREDPROPAGATION_REQUIRED,readOnly(4)使用)使用TransactionProxyFactoryBean:PROPAGATION_REQUIRED:支持当前的事务,如果不存在就 创建一个新的。这是最常用的选择。:支持当前的事务,如果不存在就 创建一个新的。这是最常用的选择。PROPAGATION_SUPPORTS:支持当前的事务,如果不存在就 不使用事务。:支持当前的事务,如果不存在就 不使用事务。PROPAGATION_MANDATORY:支持当前的事务,如果不存在 就抛出异常。:支持当前的事务,如果不存在 就抛出异常。PROPAGATION_REQUIRES_NEW:创建一个新的事务,并暂 停当前的事务(如果存在)。:创建一个新的事务,并暂 停当前的事务(如果存在)。PROPAGATION_NOT_SUPPORTED:不使用事务,并暂停当前 的事务(如果存在)。:不使用事务,并暂停当前 的事务(如果存在)。PROPAGATION_NEVER:不使用事务,如果当前存在事务就抛 出异常。:不使用事务,如果当前存在事务就抛 出异常。PROPAGATION_NESTED:如果当前存在事务就作为嵌入事务执 行,否则与:如果当前存在事务就作为嵌入事务执 行,否则与PROPAGATION_REQUIRED类似。类似。元素的元素的key属性决定代理将为方法提供什么样的事务行为。这 个属性的最重要部分就是事务传播行为。下面是一些可选的属性值:属性决定代理将为方法提供什么样的事务行为。这 个属性的最重要部分就是事务传播行为。下面是一些可选的属性值:前前6个事务策略与个事务策略与EJB的的CMT类似,而且使用相同的常量名,因此对 类似,而且使用相同的常量名,因此对 EJB开发人员来说是很亲切的。第开发人员来说是很亲切的。第7个策略个策略PROPAGATION_NESTED是 是 Spring提供的一个变体:它需要事务管理器(如提供的一个变体:它需要事务管理器(如DataSourceTransactionManager)提供类似)提供类似J DBC3.0那样的保存点那样的保存点 API来嵌套事务行为或者通过 来嵌套事务行为或者通过 JTA支持嵌套事务。支持嵌套事务。TransactionProxyFactoryBean只是组件的事务代理,如果我们要给组 件添加一些业务方面的验证,可以使用只是组件的事务代理,如果我们要给组 件添加一些业务方面的验证,可以使用TransactionTemplate加拦截器方 式,为组件添加多个拦截器,加拦截器方 式,为组件添加多个拦截器,spring AOP中提供了三类中提供了三类Advice,即前增 强,后增强,抛出异常时的增强,可以灵活使用。如果只有很少的事务操作,使用编程式事务管理才是个好主意。例 如,如果有一个,即前增 强,后增强,抛出异常时的增强,可以灵活使用。如果只有很少的事务操作,使用编程式事务管理才是个好主意。例 如,如果有一个Web应用需要为某些更新操作提供事务,可能不想用 应用需要为某些更新操作提供事务,可能不想用 Spring或其它技术设置一个事务代理。使用或其它技术设置一个事务代理。使用TransactionTemplate可能是个 很好的方法。另一方面,如果应用有大量的事务操作,声明式事务管理就很有价值。它使得事务管理从业务逻辑分离,并且可能是个 很好的方法。另一方面,如果应用有大量的事务操作,声明式事务管理就很有价值。它使得事务管理从业务逻辑分离,并且Spring中配置也不困难。使用 中配置也不困难。使用 Spring,而不是,而不是EJB CMT,极大地降低了声明式事务管理配置的成本。,极大地降低了声明式事务管理配置的成本。实践项目实践项目 一、程序的实现要求如下:(一、程序的实现要求如下:(1)Spring与与JDBC结合实现向数据库表中添 加数据的操作。(结合实现向数据库表中添 加数据的操作。(2)要求实现参数化配置的事务管理。)要求实现参数化配置的事务管理。二、实现步骤二、实现步骤(1)在)在Spring的配置文件中,我们需要对数据源进行配置以及 以参数化的形式进行事务管理的配置。下面的配置中,通过 的配置文件中,我们需要对数据源进行配置以及 以参数化的形式进行事务管理的配置。下面的配置中,通过 UserDAOProxy节点配置了一个针对节点配置了一个针对userDao Bean的事务代理(由的事务代理(由target属性指定)。通过属性指定)。通过transactionAttributes属性,我们 指定了事务的管理策略,即对所有以属性,我们 指定了事务的管理策略,即对所有以insert开头的方法进行事务 管理,如果被管理方法抛出异常,则自动回滚方法中的事务,如果成功执行,则在方法完成之后进行事务提交。另一方面对 于其它方法(通过通配符开头的方法进行事务 管理,如果被管理方法抛出异常,则自动回滚方法中的事务,如果成功执行,则在方法完成之后进行事务提交。另一方面对 于其它方法(通过通配符*表示),则进行只读事务管理,以获 得更好的性能。表示),则进行只读事务管理,以获 得更好的性能。(2)下面是)下面是DAO设计,在设计,在insertUser()方法中实现数据的添加功能。方法中实现数据的添加功能。public class UserDao private DataSource dataSource;private PlatformTransactionManager transactionManager;public PlatformTransactionManager getTransactionManager()return transactionManager;public void setTransactionManager(PlatformTransactionManager transactionManager)this.transactionManager=transactionManager;public DataSource executeTestSource()return dataSource;public void setDataSource(DataSource dataSource)this.dataSource=dataSource;public void insertUser()JdbcTemplate jt=new JdbcTemplate(executeTestSource();jt.update(insert into users(username)values(Lily););本章总结本章总结 SpringSpring事务管理的概念事务管理的概念 SpringSpring事务抽象事务抽象 SpringSpring事务策略事务策略 SpringSpring提供的事务管理提供的事务管理 使用使用SpringSpring编程式的事务处理编程式的事务处理 使用使用SpringSpring声明式的事务处理声明式的事务处理
展开阅读全文