Spring学习笔记---5-Spring事务管理(1)

来源:互联网 发布:python split删除空格 编辑:程序博客网 时间:2024/06/10 19:44
一、事务的基础知识

      Spring提供了灵活方便Dev事务管理功能,这些功能是基于底层数据库本身的事务处理机制工作的。那我们在了解Spring的事务管理和配置之前,先了解一下数据库事务的基础知识。
       事务有四大特性:原子性,一致性,隔离性、持久性等。
       原子性:指的是一个事务的最小的单位是原子,如果在一个数据库语句中,有多个sql组成,则每条sql就是这个大sql的原子,如果有一条sql执行失败,那就意味着这一大条的sql执行失败,那么之前执行过的sql就必须重新回滚到最初状态,用最恰当的比喻就是“一荣俱荣,一损俱损”;如果成功,则整条语句都执行成功,否则都失败,回到之前的状态。
       一致性:大家都用转账的时候A账户和B账户之间的总的金额保持不变来说明一致性。注解:其实这句话的意思是如果事务没有成功,则一定要完全回滚,如果成功了,则一定要保证数据的正确性。
      隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会被对方产生干扰。准确的说,并非要求做到完全无干扰,数据库规定了各种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。注解:指的是事务与事务之间的无关性,不会因为一个事务的发生去影响另一个事务的数据。
       持久性:一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须保证能够通过某种机制恢复数据。

       在上面的事务特性中,数据“一致性”是最终目标,其他的特性都是为达到这个目标的措施、要求和手段。注解:这句话是完全正确的。

      数据库管理系统一般采用重执行日志保证原子性、一致性和持久性,重执行日志记录了数据库变化的每一个动作,数据库在一个事务中执行一部分操作后发生错误退出,数据库即可以根据重执行日志撤销已经执行的操作。此外,对于已经提交的事务,即使数据库崩溃,在重启数据库时也能够根据日志对尚未持久化的数据进行相应的重执行操作。

       和Java程序采用对象锁机制进行线程同步类似,数据库管理系统采用数据库锁机制保证事务的隔离性。当多个事务试图对相同的数据进行操作时,只有持有锁的事务才能操作数据,知道前一个事务完成后,后面的事务才有机会对数据进行操作。

       注解:上面讲的都是数据库事务的实现,在数据库系统中怎么对每一条sql或者多条sql进行事务处理的:事务锁机制--也就是锁表或者锁行机制;当前对同一行后者同一个表的操作只能是一个事务操作。
       问题是:这个是事务的基础知识,我是要通过应用程序管理事务来对数据库进行操作,我知道了数据库的事务,那跟我学习应用程序管理事务有什么关系?请看下面?

二、JDBC对的事务支持

      在上面讨论了数据库的事务机制之后,我应该去探究一下JDBC的事务了,毕竟我不能任何sql语句都写在存储过程里,让数据库系统去自己去管理事务吧(我就经历过这样的项目,结果是存储过程没人敢修改,因为不知道这个存储过程有没有在别的地方被修改,代码一团糟,人人都希望能够重写项目)。
       
      我知道了数据库的事务机制,但是我也知道,并不是所有数据库系统都有事务支持的,mysql中插件式的存储引擎中就有好几个是不支持事务机制的。所以在最接近数据库的应用程序--JDBC是怎么来支持事务的呢?答案是手动支持。
      代码如下:
       
      一如代码中,这个是大家在学习Java时都会学到的一段代码,先链接链接,然后建立一个sql对象,然后执行sql。在上面的代码中增加几行代码:关闭自动提交的机制,设置了事务隔离级别,提交事务,并回滚事务。
   
       补充:Connection默认情况下是自动提交的,即每条执行的sql都对应一个事务。为了将多条sql当做一个事务来执行,则必须阻止其自动提交:conn.setAutoCommit(false); 

       其中的conn.commit();就是提交事务,如果提交失败了,则回滚:conn.rollback();

       问题来了:我执行了conn.commit(); 是怎么提交的?
                       我执行了conn.rollback(); 又是怎么回滚的?怎么做到的呢?   
       这个问题中所用到的JDBC其实是将配置文件中的数据库连接池中的信息,一条sql就是使用数据库连接池中的一个连接,一个事务。如果能够做到,如果在事务提交时,如果失败,执行回滚的话,其实调用的是数据库本身的回滚机制。

三、Spring是事务管理的支持

      Spring为事务管理提供了一致的编程模型,在高层次建立了统一的事务抽象。也就是说无论是SpringJDBC、Hibernate或者其他的工具,Spring都让用户可以用统一的编程模型进行事务管理(天下一统)。
      Spring事务管理继承了这一风格,也提供了事务模板类TransactionTemplate。通过TransactionTemplate 并配合使用事务回调TransactionCallback 指定具体的持久化操作就可以通过编程方式实现事务管理,而无须关注资源获取,复用、释放、事务同步和异常梳理的操作
       注解:也就是说Spring对事务管理进行统一管理,只需要采用Spring提供的模板:TransactionTemplate,即可。至于资源的获取,复用,释放,事务同步,异常处理等统统不用操心,Spring会帮我们做。

       如果你觉得到这里已经觉得Spring真的是劳苦功高啊,别着急,Spring还有更大的绝招:声明式事务管理。Spring运行通过声明方式,在IOC配置中指定事务的边界和事务属性,Spring自动在制定的事务边界上应用事务属性。这种声明式事务一直是EJB引以为傲的,现在Spring让事务管理更加平民化。(到这里就只剩下对Spring顶礼膜拜了吧)

      Spring认识到,在大部分的应用中我们都会使用单个的数据源,只有很少的应用会用到多数据源。因此在但数据源的情况下,Spring直接使用底层的数据管理事务。而如果我们用的是多数据源的JTA事务,Spring才需求JavaEE应用服务器的支持,通过引用应用服务器中的JNDI资源完成ITA事务。
  
      注解:无论我们采用的是但数据源还是多数据源,都可以使用Spring提供的相同的事务管理模型。 

四、事务管理关键抽象

      在Spring事务管理SPI (Service Privider Interface)的抽象层主要包括3个接口,分别是 PlatformTransactionManager、TransactionDefinition 和 TransactionStatus,他们位于 org.springframework.transaction 包中。
      下图描述三者关系:
        
TransactionDefinition 用于描述事务的隔离级别、超时时间、是否为只读事务和事务传播规则等控制事务具体行为的事务属性,这些事务属性可以通过XML配置或注解描述提供,也可以通过手工编程的方式设置。
PlatformTransactionManagerg根据TransactionDefinition 提供的事务属性配置信息,创建事务,并用TransactionStatus描述这个激活事务的状态。
解释:不要被上面的没见过的Spring类给吓着,你打开这个来就知道了,如下:
  1. public interface TransactionDefinition {
  2. int PROPAGATION_REQUIRED = 0;
  3. int PROPAGATION_SUPPORTS = 1;
  4. int PROPAGATION_MANDATORY = 2;
  5.       int PROPAGATION_REQUIRES_NEW = 3;
  6.      ……
  7.   }   
          TransactionDefinition 定了Spring兼容的事务属性,这些属性对事务管理控制的若干方面进行配置。
   事务隔离:当前事务和其他事务隔离的程度;如:
    
   事务传播:Spring定义了几个传播类型;
   事务超时:事务在超时前运行多久,超时时间后,事务被回滚。
   只读状态:只读事务不修改任何数据。
          Spring运行通过XML或注解元数据的方式为一个有事务要求的服务类方法配置事务属性,这些信息将作为Spring事务管理框架的”输入“,Spring将自动按事务属性信息的指示,为目标提供相应的事务支持。
解释:上面的这段话读着有点云里雾里的,其实要表达的意思是:Spring的事务管理将会采用AOP的支持,为目标类提供事务支持。而配置的事务属性会采用IOC,将属性注入到目标类中。
   IOC对配置的属性支持,AOP对配置的目标方法,结合起来对Spring的事务管理进行支持。

五、Spring事务管理器实现类

      spring将事务管理委托给底层具体的持久化实现框架完成,因此Spring为不同的持久化框架提供了PlatformTransactionManagerg接口的实现类。
   如图:
   这些事务管理器都是针对特定框架的,这样,用户就可以通过Spring所提交的高级抽象对不同种类的事务使用相同的方式进行管理,而不用关心具体的实现。解释:不同的框架使用不同的事务管理器。
  要实现事务管理,首先要在Spring中配置好相应的事务管理器,为事务管理器指定数据资源以及一些其他事务管理控制属性。

六、事务同步管理器

       Spring将JDBC的Connection、Hibernate的Session等访问数据库的链接或会话对象统称为资源。这些资源在同一时刻是不能多线程共享的(注解:防止线程中数据错乱,必须不能共享),为了让Dao、Service类可能做到singleton,Spring的事务同步管理器类org.springframework.transaction.support.TransactionSynchronizationManager使用ThreadLocal管理为不同事务线程提供了独立的资源副本,同时维护事务配置的属性和运行状态信息。事务同步管理器是Spring事务管理的基石部分,不管用户使用的是编程式事务管理,还是声明式事务管理,都离不开事务同步管理器。
     Spring为不同的持久化技术提供了模板类,模板类在内部通过资源获取工具类间接访问TransactionSynchronizationManager中的线程绑定资源。因此,如果Dao使用模板类进行持久化操作,这些Dao就可以配置成singleton。如果不适用模板类,也可直接通过资源获取工具类访问线程相关的资源。
     解释:经验,项目中很少会脱离模板类去获取线程中资源的。

七、事务传播行为

      当调用一个基于Spring的Service接口方法(如UserService#addUser())时,它将运行与Spring管理的事务环境中,Service接口方法可能会在内部调用其他Service接口方法以共同完成一个完整的业务操作,因此就会产生服务接口方法嵌套调用的情况,Spring通过事务传播行为控制当前的事务如何传播到被嵌套的目标服务接口方法中。事务传播是Spring进行事务管理的重要概念。
      Spring在TransactionDefinition接口中规定了7中类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,
     如图:
              
      当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC3.0,并且实现者需要支持保存点事务机制。


八、设计原理和基本过程

          在使用Spring声明式事务处理的时候,一种常用的方法是结合IOC容器和Spring已有的TransactionProxyFactoryBean对事务管理进行配置,比如,可以在这个TransactionProxyFactoryBean中为事务方法配置传播行为、并发事务隔离级别等事务处理属性,从而对声明式事务的处理提供指导。声明式事务处理的实现大致可以分为以下几个部分:
        1、读取和处理在IOC容器中配置的事务处理属性,并转化为Spring事务处理需要的内部数据结构。具体来说,这里涉及的类是TransactionAttributeSourceAdvisor,从名字可以看出,它是一个AOP通知器,Spring使用这个通知器来完成对事务处理属性值的处理。处理的结果是,在IOC容器中配置的事务处理属性信息,会被读入并转化成TransactionAttribute表示的数据对象,这个数据对象是Spring对事务处理属性值的数据抽象,对这些属性的处理时和TransactionProxyFactoryBean拦截下来的事务方法的处理结合起来的。
        2、Spring事务处理模块实现统一的事务处理过程。这个通用的事务处理过程包含处理事务配置属性,以及与线程绑定完成事务处理的过程。Spring通过TransactionInfo和TransactionStatus这两个数据对象,在事务处理过程中记录和传递相关执行场景。
        3、底层的事务处理实现。对于底层的事务操作,Spring委托给具体的事务处理器来完成,这些具体的事务处理器,就是在IOC容器中配置声明式事务处理时,配置的PlatformTransactionManager的具体实现,比如DataSourceTransactionManager和HibernateTransactionManager等。



0 0
原创粉丝点击