【Spring】【笔记】《Spring In Action》第6章 事务管理

来源:互联网 发布:土建预算软件下载 编辑:程序博客网 时间:2024/06/05 21:49
     事务 transaction : 全有或全无的操作

6.1 理解事务

6.1.1 事务的特性
     这里可以参照数据库原理中对事务的描述
  • 原子性 Atomic:事务是由一个或多个活动组成的一个工作单元,原子性确保事务中的所有操作全部发生或全部不发生
  • 一致性 Consistent:一旦事务完成,无论成功或失败,系统必须确保他所建模的业务处于抑制的状态。
  • 隔离性 Isolated:事务允许多个用户对相同的数据进行操作,每个用户的操作不会与其他用户纠缠到一起。因此,事务应该被彼此隔离,避免发生同步读写相同数据的事情
  • 持久性 Durable:一旦事务完成,事务的结果应该持久化,这样就能从任何的系统崩溃中恢复过来。这一般会设计将结果存储到数据库或其他形式的持久化存储中
     这里事务的概念与数据库理论中的事务是一致的。

6.1.2 Spring对事务管理的支持

     Spring提供了对编码式和声明式事务管理的支持。
     Spring通过回调机制将实际的事务实现从事务性的代码中抽象出来,Spring对事务的支持可以不需要JTA的实现。
JTA,即Java Transaction API,JTA允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据
     如果应用程序只使用一种持久化资源,Spring可以使用持久化机制本身所提供的事务性支持,包括JDBC、Hibernate、JPA。但是如果应用程序的事务跨多个资源,那么Spring会使用第三方的JTA实现来支持分布式(XA)事务。

     编码式事务允许用户在代码中精确定义事务的边界,声明式事务(基于AOP)有助于用户将操作与事务规则进行解耦。

6.2 选择事务管理器
     Spring并不直接管理事务,而是提供了多种事务管理器。他们将事务管理的职责委托给JTA或其他持久化机制所提供的平台相关的事务实现。
     Spring的事务管理器:
事务管理器 org.framework.*使用场景jca.cci.coonection.CciLocalTransactionManager使用Spring对JavaEE连接器架构(Java EE Connector Architecture,JCA)和通用客户端接口(Common Client Interface,CCI)提供支持jdbc.datasource.DataSourceTransactionManager用于Spring对JDBC抽象的支持,也可用于使用iBATIS进行持久化的场景jms.connection.JmsTransactionManger用于JMS1.1+jms.connection.JmsTransactionManager102用于JMS1.0.2orm.hibernate3.HibernateTransactionManager用于Hibernate3进行持久化orm.jdo.JdoTransactionManager用于JDO进行持久化orm.jpa.JpaTransactionManager用于Java持久化API(Java Persistence API,JPA)进行持久化transaction.jta.JtaTransactionManager需要分布式事务或没有其他的事务管理器满足需求transaction.jta.OC4JJtaTransactionManager用于Oracle的OC4J JEE容器transaction.jta.WebLogicJtaTransactionManager需要使用分布式事务并且应用程序运行于WebLogic中transaction.jta.WebSphereUowTransactionManager需要WebSphere中UOWManager所管理的事务
     要使用事务管理器,需要将其生命在应用程序上下文中。

6.2.1 JDBC事务
     如果在应用程序中直接使用JDBC来进行持久化,DataSourceTransactionManager会处理事务边界。要使用DataSourceTransactionManager,需要如下装配:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"/>
     <property name="dataSource" ref="dataSource"/>
</bean>
     这里dataSource配置成一个名为dataSource Bean的引用,而dataSource是定义在上下文文件中的javax.sql.DataSource Bean。
     DataSourceTransactionManager通过调用java.sql.Connection来管理事务,后者是通过DataSource获取到的。通过调用连接的commit()提交事务,rollback()方法进行回滚。

6.2.2 Hibernate事务
     如果使用Hibernate实现应用程序的持久化,那么需要使用HibernateTransactionManager。需如下配置:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"/>
     <property name="sesionFactory" ref="sessionFactory"/>
</bean>
     sessionFactory属性需要装配一个HibernateSessionFactory。(无论是Spring3.0 还是Spring2.5都不包含对Hibernate2的支持,只有Spring2.0是支持的)
     HibernateTransactionManager将事务管理委托给org.hibernate.Transaction对象,后者是从HibernateSession中获得的。事务成功完成时,HibernateTransactionManager将会调用Transaction对象commit()方法。如果事务失败,Transaction对象的rollback()方法将会被调用

6.2.3JPA事务
     使用JPA 需要用Spring的JpaTransactionManager来处理事务,需要如下配置:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
     <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
     JpaTransactionManager只需要装配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现)。JpaTransactionManager将与由工厂所产生的JPA EntityManager合作来构建事务。。
     JpaTransactionManager支持将事务应用于简单的JDBC操作之中,这些JDBC操作所使用的DataSource与EntityManagerFactory所使用的DataSource必须是相同的。为了做到这一点,JpaTransactionManager必须装配一个JpaDialect的实现。

eg:
EclipseLinkJpaDialect
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
将jpaDialect Bean装配到JpaTransactionManager中
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
     <property name="entityManagerFactory" ref="entityManagerFactory"/>
     <property name="jpaDialect" ref="jpaDialect"/>
</bean>
     JpaDialect实现必须同时支持JPA/JDBC访问。所有Spring所支持的特定厂商JpaDialect实现都提供了对JPA和JDBC混合的支持,而DefaultJpaDialect并不支持。

6.2.4 JTA事务
     在其他事务管理器满足不了、或事务需要跨资源使用时,需要使用JtaTransactionManager:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
     <property name="transactionManagerName" value="java:/TransactionManager" />
</bean>
     JtaTransactionManager将事务管理委托给一个JTA的实现。JTa规定了应用程序与一个或多个数据源协调事务的标砖API。transactionManagerName属性指明了要在JNDI上查找的JTA事务管理器。

6.3 Spring编码事务

eg:

saveSpittle()

public void saveSpittle(Spittle spittle) {
     spitterDao.saveSpittle(spittle);
}
添加编码事务
public void saveSpittle(final Spittle spittle) {
     txTemplate.execute(new TransactionCallback<Void>() {     //这里为什么是Void,不太理解
          public Void doInTransaction(TransactionStatus txStatus) {
               try {
                    spitterDao.saveSpittle(spittle);
               } catch(RuntimeException e) {
                    txStatus.setRollbackOnly();
                    throw e;
               }
               return null;
          }
     });
}

     为了使用TransactionTemplate,需要实现TransactionCallBack接口。因为TransactionCallback只有一个要实现的方法,通常会简单的将其实现为匿名内部类。将事务性的代码放在doInTransaction()方法中。
     调用TransactionTemplate实例的execute()方法时,将会执行TransactionCallback实例中的代码。如果代码遇到了问题,调用TransactionStatus对象的setRollbackOnly()方法将回滚事务。否则,如果doInTransaction()成功返回,事务将会提交。
     TransactionTemplate实例需要注入到SpitterServiceImpl中

<bean id="spitterService" class="com.habuma.spitter.service.SpitterServiceImpl">
     ...
     <property name="transactionTemplate">
          <bean class="org.springframework.transaction.support.TransactionTemplate">
               <property name="transactionManager" ref="transactionManager"/>
          </bean>
     </property>
</bean>
     TransactionTemplate需要注入一个transactionManager。实际上TransactionTemplate使用了PlatformTransactionManager实现来处理特定平台的事务管理细节。这里装配的transactionManager的Bean引用,可以是Spring提供的任意一个事务管理器。

     编程式事务是具有侵入性的。因此,在不需要极小粒度的事务控制时,声明式事务是更好的选择。

6.4 声明式事务
     通过AOP实现。

6.4.1 定义事务的属性
     Spring中,声明式事务是通过 事务属性(transaction attribute)来定义的。是无属性描述了事务策略如何应用到方法上。事务属性包含了五个方面:传播行为、隔离级别、hi滚规则、事务超时、是否只读
     Spring所有的声明式事务机制都依赖这5个参数来控制如何管理实务策略。

传播行为
     propagation behavior。定义客户端与被调用方法之间的事务边界。Spring定义了7种不同的传播行为
传播行为含义PROPAGATION_ MANDATORY表示该方法必须在事务中运行,如果当前事务不存在,抛出一个异常PROPAGATION_NESTED表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独的提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。歌唱声对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确定他们是否支持嵌套式事务PROPAGATION_NEVER表示当前方法不应该运行在事务上下文中。如果当前争优一个事务在运行,抛出异常PROPAGATION_NOT_SUPPORTED表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManagerPROPAGATION_REQUIRED表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务PROPAGATION_REQUIRES_NEW表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionMangager,则需要访问TransactionManagerPROPAGATION_SUPPORTS表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行。
     
     传播规则规定了,新的事务应该被启动还是挂起、方法是否需要在事务环境中运行。

隔离级别
     isolation level。定义了一个事务可能受其他并发事务影响的程度。理想情况下,事物之间是完全隔离的,但这会导致性能问题。
隔离级别含义ISOLATION_DEFAULT适用后端数据库默认的隔离级别ISOLATION_READ_UNCOMMITTED允许读取尚未提交的数据变更。可能导致脏读、幻读、不可重复读ISOLATION_READ_COMMITTED允许读取并发事务已经提交的数据。可能发生幻读、不可重复度ISOLATION_REPEATABLE_READ对同一字段的多次读取结果是一只的,除非数据被本事务自己修改。可能发生幻读ISOLATION_SERIALIZABLE完全服从ACID的隔离级别,确保阻止脏读、不可重复度、幻读。最慢的事务隔离级别,通过完全锁定事务相关的数据库表来实现。
     隔离级别定义在org.springframework.transaction.TransactionDefinition接口中
     并不是所有数据源都支持这些隔离级别

只读
     如果食物支队后端的数据库进行读操作,数据库可以利用食物的之独特性来进行一些特定的优化。
     制度优化是在事务启动的时候由数据库实时的,只有对那些具备启动一个新的事务的传播行为的方法,将事务声明为只读才有意义。包括:PROPAGATION_REQUIRED/PROPAGATION_REQUIRES_NEW/PROPAGATION_NESTED

事务超时
     超时始终会在事务开始时启动,只有对那些具备启动一个新事物的传播性为的方法,设置事务超时才有意义。包括:PROPAGATION_REQUIRED/PROPAGATION_REQUIRES_NEW/PROPAGATION_NESTED

回滚规则
     规定哪些异常会导致事务回滚,哪些不会。默认情况下,事务只有在遇到RuntimeException时才会回滚,检查性异常时不会回滚。

6.4.2 在XML中定义事务
     spring提供了一个tx配置命名空间,用来配置Spring中的声明式事务。
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:aop="http://www.springframework.org/schema/aop"
     xmlns:tx="http://www.springframework.org/schema/tx"
     xsi:schemaLocation=" http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/aop
          http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
          http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx-3.0.xds">
     注意,aop命名空间也应该包括在内

     <tx:advice>
<tx:advice id="txAdvice">
     <tx:attributes>
          <tx:method name="save*" propagation="REQUIRED"/>
          <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
     </tx:attribute>
</tx:advice>
     事务属性定义在<tx:attributes>元素中,<tx:method>元素为相应的属性指定参数
     <tx:method>对事务属性的定义:
隔离级别含义isolation指定事务的隔离级别propagation事务的传播规则read-only指定事务为只读
rollback-for
no-rollback-for
指定事务对于哪些检查性异常应当回滚而不提交
指定事务对于哪些异常应当继续运行而不会滚
timeout超时时间
     使用<tx:advice>来声明事务时,需要一个事务管理器。根据约定优于配置,<tx:advice>嘉定事务管理器被声明为一个id为transactionManager的Bean。如果事务管理器配置了其他的id,例如txManager,则需要在transactionmanager属性中明确指定事务管理器的id:
<tx:advice id="txAdvice" transaction-manager="txManager">
     ..
</tx:advice>

     <tx:advice>只是定义了AOP通知,用于把事务边界通知给方法。但是这只是事务通知,而不是完整的事务性切面。需要一个切点来声明那些Bean应该被通知,因此为了完整定义事务性切面,需要定义一个通知器advisor。
eg:
<aop:config>
     <aop:advisor
          point-cut="execution(* *..SpitterService.*(..))"
          advice-ref="txAdvice"/>
</aop:config>

6.4.3 定义注解驱动的事务
     
<tx:annotaion-driven> //就可以了

     可以通过transactionmanager属性(默认为transactionManager)来指定特定的事务管理器
<tx:annotaion-driven transaction-manager="txManager"/>
   
     <tx:annotaion-driven>元素告诉Spring检查上下文中所有的Bean并查找使用@Transactional注解的Bean,无论这个注解用于类级别还是方法级别。对于每一个使用@Transactional注解的Bean,<tx:annotaion-driven>会自动为它添加事务通知。通知的事务属性时通过@Transaction注解的参数来定义的。
eg:
@Transational(propagation=Propagation.SUPPORTS,readOnly=true)
public class SpitterServiceImpl implements SpitterService {
...
     @Transactional(propagation=PROPGATION.REQUIRED, readOnly=false)
     public void addSpitter(Spitter spitter) {
...
     }
...
}
     
     在类级别上使用@Transactional注解表示所有的方法都支持事务。



第6章小结

     Spring同时支持编码式和声明式的事务管理。无论按一种方式,Spring都将事务管理平台抽象为通用的API,避免了直接与特定的事务管理器实现进行交互。






1 0
原创粉丝点击