spring事务管理及相关知识

  最近在项目中遇到了spring事务的注解及相关知识,突然间感觉自己对于这部分知识只停留在表面的理解层次上,于是乎花些时间上网搜索了一些文章,以及对于源码的解读,整理如下:  

  一.既然谈到事务,那就先搞清到底什么是事务,或者说,Spring事务管理中的事务到底是指什么? 

  1.事务(Transaction),通常是指数据库的事务,在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit),例如insert 、update、delete等,事务是恢复和并发控制的基本单位。 

  2.事务具有四种属性(ACID特性): 

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

一致性(consistency)。是指当事务完成时,必须使所有数据都具有一致的状态,事务必须是使数据库从一个一致性状态变到另一个一致性状态,一致性与原子性是密切相关的。

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

持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

  二.事务的管理  

  1.spring 如何来管理事务呢,查看源码发现,一般我们在配置文件中声明的如<bean name="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">或者是其他的Manager,均继承自    

org.springframework.transaction.PlatformTransactionManager,而PlatformTransactionManager.java中定义了以下几种方法,源码如下:

package org.springframework.transaction;

public abstract interface PlatformTransactionManager {

public abstract TransactionStatus getTransaction(TransactionDefinition paramTransactionDefinition)     throws TransactionException;

public abstract void commit(TransactionStatus paramTransactionStatus)     throws TransactionException;

public abstract void rollback(TransactionStatus paramTransactionStatus)     throws TransactionException;

}

   下面来具体分析一下:

   1.1.TransactionDefinition.java,这个类(确切的说是接口)是事务的定义类,此接口指定了事务隔离级别、事务传播属性、事务超时、只读状态。
       1.2.TransactionStatus接口。这个接口为处理事务提供简单的控制事务执行和查询事务状态的方法。

  1.3.事务的传播属性: 

   PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
       PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
       PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
       PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
       PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
       PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与REQUIRED类似的操作。拥有多个可以回滚的保存点,内部回滚不会对外部事务产生影响。只对DataSourceTransactionManager有效

   1.4.事务的隔离级别:

ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
      另外四个与JDBC的隔离级别相对应 

ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
      ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
      ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
      ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。  

  1.5.名词解释:什么是脏数据,脏读,不可重复读,幻觉读,事务的挂起?

  脏读: 指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

  不可重复读: 指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

  幻觉读: 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。

  挂起:例如,方法A支持事务,方法B不支持事务,方法A调用方法B。 在方法A开始运行时,系统为它建立Transaction,方法A中对于数据库的处理操作,会在该Transaction的控制之下。 这时,方法A调用方法B,方法A打开的 Transaction将挂起,方法B中任何数据库操作,都不在该Transaction的管理之下。 当方法B返回,方法A继续运行,之前的Transaction回复,后面的数据库操作继续在该Transaction的控制之下 提交或回滚。

  2.spring事务管理的两种方式:

  2.1.声明式事务管理 (分为两种,基于XML配置方式和基于注解配置方式)

  如果并不需要细粒度的事务控制,可以使用声明式事务,在Spring中,只需要在Spring配置文件中做一些配置,即可将操作纳入到事务管理中,解除了和代码的耦合,这是对应用代码影响最小的选择,从这一点再次验证了Spring关于AOP的概念。当不需要事务管理的时候,可以直接从Spring配置文件中移除该设置.需要引入用于事务管理的命名空间(tx).

  Spring并没有直接管理事务,而是将事务的管理委托给其他的事务管理器实现.

  Spring支持的事务管理器:

  • org.springframework.jdbc.datasource.DataSourceTransactionManager (在单一的JDBC Datasource中的管理事务)
  • org.springframework.orm.hibernate3.HibernateTransactionManager (当持久化机制是hibernate时,用它来管理事务)
  • org.springframework.jdo.JdoTransactionManager (当持久化机制是Jdo时,用它来管理事务)
  • org.springframework.transaction.jta.JtaTransactionManager (使用一个JTA实现来管理事务。在一个事务跨越多个资源时必须使用)
  • org.springframework.orm.ojb.PersistenceBrokerTransactionManager (当apache的ojb用作持久化机制时,用它来管理事务)

  第一种.基于XML配置方式

<!--1 配置数据源-->
<bean id="dateSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="username" value="root"/>
   <property name="password" value="root"/>
   <property name="url" value="jdbc:mysql://localhost:3306/test"/>
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
   <property name="maxActive" value="100"/>
    <!-- 初始化连接数 -->
   <property name="initialSize" value="5"/>
   <!--最大空闲数,当洪峰退去时, 连接池所放的最少连接数-->
   <property name="maxIdle" value="8"/>
   <!--最小空闲数,当洪峰到来时,引起的性能开销 -->
   <property name="minIdle" value="5"/>
</bean>
<!--2 配置JdbcTemplate模板,类似于dbutils,可数据访问操作-->  
<bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!-- 给JdbcTemplate注入数据源,调用JdbcAccessor中的setDataSource(DataSource dataSource)注入数据源-->
    <property name="dataSource" ref="dateSource"/>
</bean>  
<!-- 3 声明事务管理器(实际上,事务管理器就是一个切面),事务管理器将在获取连接时,返回一个打开事务的连接 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 注入数据源,spring的jdbc事务管理器在管理事务时,依赖于JDBC的事务管理机制 -->
    <property name="dataSource" ref="dateSource"/>
</bean> 
<!-- 4 配置通知 
     id="advice":该属性的值就是通知的唯一标识
     transaction-manager:表示通知织入哪个切面
-->
<tx:advice id="advice" transaction-manager="txManager">
  <tx:attributes>
    <!-- tx:method的属性:
          * name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配符(*)可以用来指定一批关联到相同的事务属性的方法。
                    如:‘get*‘、‘handle*‘、‘on*Event‘等等.
          * propagation  不是必须的 ,默认值是REQUIRED 
                            表示事务传播行为, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
          * isolation    不是必须的 默认值DEFAULT 
                            表示事务隔离级别(数据库的隔离级别) 
          * timeout      不是必须的 默认值-1(永不超时)
                            表示事务超时的时间(以秒为单位) 
          * read-only    不是必须的 默认值false不是只读的 
                            表示事务是否只读          
          * rollback-for 不是必须的   
                            表示将被触发进行回滚的 Exception(s);以逗号分开。
                            如:‘com.foo.MyBusinessException,ServletException‘       
          * no-rollback-for 不是必须的  
                              表示不被触发进行回滚的 Exception(s);以逗号分开。
                              如:‘com.foo.MyBusinessException,ServletException‘               
        任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚                -->
     <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
     <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
     <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
     <!-- 其他的方法只读的 -->
     <tx:method name="*" read-only="true"/>
  </tx:attributes>
</tx:advice>
<!-- 5 配置切入点 -->
<aop:config>
  <!-- 定义切入点,可以定义到类中所有的方法,之后在事务中在对方法进行细化 -->
  <aop:pointcut id="perform" expression="execution(* *.*(..))"/>
  <!-- 将通知和切入点关联起来-->
  <aop:advisor advice-ref="advice" pointcut-ref="perform"/>
</aop:config> 

配置完事务管理器后,再常规的配置Bean注入对象.默认只有运行时异常才将导致事务回滚.

  第二种.基于注解配置方式

XML配置文件中只需要声明事务管理器,而不需要给它"灵魂",因为"灵魂"是由注解注入,所以需要注解解析器的支持:

<tx:annotation-driven transaction-manager="txManager"/>

注册对事务注解进行解析的处理器,将注解与事务管理器关联起来即可.

/**
 *   方法的事务设置将被优先执行。
 *   例如: BusinessService类在类的级别上被注解为只读事务,
 *   但是,这个类中的 save 方法的@Transactional 注解的事
 *   务设置将优先于类级别注解的事务设置。
 *   默认的 @Transactional 设置如下:
 *       事务传播设置是 PROPAGATION_REQUIRED
 *       事务隔离级别是 ISOLATION_DEFAULT
 *       事务是 读/写
 *       事务超时默认是依赖于事务系统的,或者事务超时没有被支持
 *       任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
 */
@Transactional(readOnly=true)
public class BusinessService {
    @Resource(name="personDao")
    private PersonDao personDao;
    @Transactional(readOnly=false,isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED)
    public void save() throws Exception{
        personDao.save();
        this.update();
    }
    public void update() throws Exception{
        personDao.save();
        personDao.update();
    }
} 

 

  2.2.编程式事务管理(也包含两种方式)

  Spring提供两种方式的编程式事务管理,分别是:使用TransactionTemplate和直接使用PlatformTransactionManager。

  第一种方式:TransactionTempale采用和其他Spring模板,如JdbcTempalte和HibernateTemplate一样的方法。它使用回调方法,把应用程序从处理取得和释放资源中解脱出来。如同其他模板,TransactionTemplate是线程安全的。代码片段:

  Object result = tt.execute(new TransactionCallback()...{

    public Object doTransaction(TransactionStatus status)...{

      updateOperation();

      return resultOfUpdateOperation();

    }

  });

  使用TransactionCallback()可以返回一个值。如果使用TransactionCallbackWithoutResult则没有返回值。

  第二种方式:使用PlatformTransactionManager直接管理事务。简单地通过一个bean引用给你的bean传递一个你使用的 PlatformTransaction对象。然后,使用TransactionDefinition和TransactionStatus对象就可以发起、回滚、提交事务。如下片段:

  DefaultTransactionDefinition def= new DefaultTransactionDefinition(); //new 一 个事务

  def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //初始化事务,参数定义事务的传播类型;

  TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态

  try...{ ……………..

    transactionManager.commit(status); //提交事务;

  }catch(…..)... {

    transactionManager.rollback(status); //回滚事务;

  }

  三.到底把事务控制在哪一层,是dao?还是service层最好?

  其实,对于数据库的操作,当然是dao层,但是,一个service中可以包含很多种dao操作,而出于对事务的特性的考虑,一般还是应该把事务控制在service层,下面是我目前项目中的配置小解:

<!--声明事务管理器-->

<bean name="transactionManager"   class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

  <property name="dataSource" ref="cc_ds"></property>  <!--注入数据源-->

</bean>

<!--配置通知-->

<tx:advice id="userTxAdvice" transaction-manager="transactionManager">

  <tx:attributes>     

    <tx:method name="find*" read-only="true"/>

    <tx:method name="get*" read-only="true"/>

    <tx:method name="select*" read-only="true"/>

    <tx:method name="*" rollback-for="java.lang.Exception"/>

  </tx:attributes>

</tx:advice>

<!--配置切入点-->

<aop:config>

  <aop:pointcut id="pc"    expression="execution(public * com.speed.*.service.impl.*.*(..))" /> <!--把事务控制在Service层 -->

  <aop:advisor pointcut-ref="pc" advice-ref="userTxAdvice" />

</aop:config>

其中public * com.speed.*.service.impl.*.*(..))" 中,public是指该事务指定公共的方法,*相当于通配符,这里第一个*是指返回值的类型,第二个包路径的一部分,也就是speed目录下的所有子模块,第三个*指定各个serviceImpl.类,第四个*是指该类下的所有方法,(..)指参列表任意,整句话就是把事务控制在service层

时间: 2024-10-17 17:53:01

spring事务管理及相关知识的相关文章

Spring事务管理(详解+实例)

写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: Spring事务机制详解 Spring事务配置的五种方式 Spring中的事务管理实例详解 1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都

Spring事务管理

写这篇博客之前我首先读了<spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: Spring事务机制详解 Spring事务配置的五种方式 Spring中的事务管理实例详解 1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都

spring事务管理——编程式事务、声明式事务

本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解.您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等.本文将直接使用这些概念而不做详细解释.另外,您最好掌握数据库的基础知识,虽然这不是必须. 系统需求 要试验这份教程中的工具和示例,硬件配置需求为:至少带有 512MB 内存(

[Spring框架]Spring 事务管理基础入门总结.

前言:在之前的博客中已经说过了数据库的事务, 不过那里面更多的是说明事务的一些锁机制, 今天来说一下Spring管理事务的一些基础知识. 之前的文章: [数据库事务与锁]详解一: 彻底理解数据库事务一, 什么是事务 事务是逻辑上一组操作,这组操作要么全都成功,要么全都失败. 事务的属性: ACID原子性(Atomicity): 事务作为一个整体被执行,包含在其中的对数据的操作要么全部被执行,要么都不执行.一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态.

(转)Spring事务管理(详解+实例)

文章转自:http://blog.csdn.net/trigl/article/details/50968079 写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: Spring事务机制详解 Spring事务配置的五种方式 Spring中的事务管理实例详解 一.初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱.  比如你去ATM机取1000块钱,

Spring事务管理全面分析

Spring 事务属性分析什么是事物  事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失.   简单来说:事物指的是逻辑上的一组操作,这组操作要么全部成功,要么全部失败.在 Spring 中,事务是通过 Tran

Spring 事务管理高级应用难点剖析--转

第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN&en=utf&hpp=20&dws=cndw&lo=zh 概述 Spring 最成功,最吸引人的地方莫过于轻量级的声明式事务管理,仅此一点,它就宣告了重量级 EJB 容器的覆灭.Spring 声明式事务管理将开发者从繁复的事务管理代码中解脱出来,专注于业务逻辑的开发上,这是一件

详细介绍Spring事务管理

在学习spring事务管理时,我忍不住要问,spring为什么进行事务管理,spring怎么进行的事务管理?首先,为什么要进行事务,接下来说说spring是怎样进行事务管理的. 我们都知道spring提供两种管理事务的方式,一种是声明式事务,一种是编程式事务. Spring的声明式事务管理,基于Spring的AOP,不再需要不停地写commit,rollback,(但Spring仍然没有放弃编程式的事务管理策略). Spring的编程式事务管理,为我们提供了一个TransactionTempla

Spring事务管理----------整合学习版

作者:学无先后 达者为先 Spring提供了一流的事务管理.在Spring中可以支持声明式事务和编程式事务. 一  spring简介 1 Spring的事务       事务管理在应用程序中起着至关重要的作用:它是一系列任务的组成工作单元,在这个工作单元中,所有的任务必须同时执行.它们只有二种可能执行结果,要么所有任务全部执行成功,要么所有任务全部执行失败.     Spring中提供了丰富的事务管理功能,它们超过了EJB并且和EJB一样支持声明式事务,重要的是Spring提供了一致的事务管理,