Spring事务管理

Spring事务管理

参考:http://www.mamicode.com/info-detail-1248286.html

基本概念

  事务是一样层层之动作,它们综合在一起才是一个完整的行事单元,那一个动作要全方位完结,如若有一个功亏一篑以来,那么事务就会回滚到绝开首之状态,仿佛什么还无起了千篇一律。就如银行之自助取款机,平时还是可以正常吗客户服务,但是也不免境遇操作过程中机器突然来故障的情形,此时,事务就务须管有故障前对账户的操作不奏效,就如用户方才完全无选择过取款机一样,以担保用户和银行之补且未被损失。
  一般的话,事务是须满意4单原则(ACID):
Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)
1、原子性:事务是一个原子操作,由同名目繁多动作结合。事务的原子性确保动作要全体做到,要么完全不起功能。
2、一致性
:满意格局锁指定的羁绊,比如银行转化前后到底金额应无换。事务了时,所有的内部数据结构(如B树引得)也都必须是科学的。
3、隔离性:事务独立运行。一个事务所做的改动以最后交由以前,对任何工作是不可见的。事务的100%切断,需要牺牲速度。
4、持久性:一旦事情完成,无论发啊系统错误,它的结果尚且非应该受震慑,这样即便会由旁系统崩溃中恢复生机过来。平日状态下,事务之结果被形容到持久化存储器中。

主干接口

  Spring事务管理涉及的接口的维系如下:
图片 1

事务管理器

  Spring并无直接管制业务,而是提供了多种事务管理器,他们以事务管理的天职委托为Hibernate或者JTA等持久化机制所提供的系平台框架的工作来贯彻。
Spring事务管理器底接口是org.springframework.transaction.PlatformTransactionManager,通过此接口,Spring为顺序平台如JDBC、Hibernate等都提供了相应的事务管理器,不过现实的落实就是各样平台好的政工了。此接口的情节如下:

Public interface PlatformTransactionManager()...{  
    // 由TransactionDefinition得到TransactionStatus对象
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
    // 提交
    Void commit(TransactionStatus status) throws TransactionException;  
    // 回滚
    Void rollback(TransactionStatus status) throws TransactionException;  
    } 

  从此间可以具体的切切实实的事务管理机制对Spring来说是晶莹剔透的,它并无关心那个,这个是本着许各种平台需关注的,所以Spring事务管理的一个亮点就是是吗不同的事务API提供相同的编程模型,如JTA、JDBC、Hibernate、JPA。上面分别介绍各样平台框架实现事务管理的机制。

JDBC事务

  假使应用程序中一贯利用JDBC、iBatis和mybatis来展开持久化,DataSourceTransactionManager会为而处理事务边界。为了选取DataSourceTransactionManager,你待用如下的XML将其配到应用程序的上下文定义着:

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

  实际上,DataSourceTransactionManager是通过调用java.sql.Connection来管理工作,而后人是经DataSource获取到之。通过调用连接的commit()方法来交付业务,同样,事务失利则经过调用rollback()方法举行回滚。
  MyBatis自动参加届spring事务管理中,无需额外部署,尽管用DataSourceTransactionManager即可。

Hibernate事务

  假诺应用程序的持久化是经Hibernate实习的,那么你得利用HibernateTransactionManager。对于Hibernate3,需要以Spring上下文定义着补充加如下的扬言:

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

  sessionFactory属性需要配一个Hibernate的session工厂,HibernateTransactionManager的实现细节是它以事务管理的天职委托给org.hibernate.Transaction对象,而后人是从Hibernate
Session中拿到到之。当事情成功就时,HibernateTransactionManager将会晤调用Transaction对象的commit()方法,反之,将会面调用rollback()方法。

Java持久化API事务(JPA)

  Hibernate多年来直接是实在的Java持久化标准,可是今Java持久化API作为真正的Java持久化标准上我们的视野。倘诺您计划采纳JPA的口舌,这你用使用Spring的JpaTransactionManager来处理事务。你得以Spring中如此安排JpaTransactionManager:

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

  JpaTransactionManager只待配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现)。JpaTransactionManager将跟由工厂所发的JPA
EntityManager合作来构建事务。

Java原生API事务

  虽然您莫拔取上述所陈述之事务管理,或者是超了多独事务管理源(比如简单独或是大抵个不等之数据源),你固然得使用JtaTransactionManager:

    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManagerName" value="java:/TransactionManager" />
    </bean>

  JtaTransactionManager将事务管理的权责委托为javax.transaction.UserTransaction和javax.transaction.TransactionManager对象,其中工作成功就经过UserTransaction.commit()方法提交,事务失利通过UserTransaction.rollback()方法回滚。

核心工作属性的定义

  上面讲到之事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition
definition)方法来得到工作,那些法中的参数是TransactionDefinition类,这多少个近乎即定义了一部分着力的事体属性。
那么什么是事情属性为?事务属性可以领略成事务之一部分主导配置,描述了事情策略如何运用及点子及。事务属性包含了5独面,如图所示:
图片 2
  而TransactionDefinition接口内容如下:

public interface TransactionDefinition {
    int getPropagationBehavior(); // 返回事务的传播行为
    int getIsolationLevel(); // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
    int getTimeout();  // 返回事务必须在多少秒内完成
    boolean isReadOnly(); // 事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的
} 

  我们可以窥见TransactionDefinition正好用来定义事务属性,上面详细介绍一下挨家挨户业务属性。

盛传行为

  事务之率先个点是流传行为(propagation
behavior)。当工作方法给别一个事务方法调用时,必须指定工作应怎么传播。例如:方法恐怕延续以现有工作中运行,也或打开一个初业务,并于自己的业务中运行。Spring定义了七种传播行为:

  • TransactionDefinition.PROPAGATION_REQUIRED:如若手上设有工作,则投入该事情;如若手上未曾事情,则开创一个新的作业。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创设一个初的事情,假使手上存工作,则把近年来工作挂于。
  • TransactionDefinition.PROPAGATION_SUPPORTS:假使手上在业务,则插手该工作;假如手上从来不事情,则盖非事务的法门继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务情势运行,如果手上存在业务,则把当前事情挂于。
  • TransactionDefinition.PROPAGATION_NEVER:以非事务格局运行,如若手上存业务,则弃来很。
  • TransactionDefinition.PROPAGATION_MANDATORY:假诺手上存在工作,则进入该业务;假设手上尚无工作,则抛来大。
  • TransactionDefinition.PROPAGATION_NESTED:尽管手上留存业务,则开创一个事情作为当前事情之嵌套事务来运作;即使手上不曾工作,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。嵌套事务一个百般紧要之概念就是内层事务倚重让外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作战败并无会面招外层事务之回滚。

断级别

  隔离级别定义了一个业务可能让另并发事务影响之品位。TransactionDefinition
接口中定义了五单象征隔离级其余常量:

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示用底层数据库的默认隔离级别。对大部分数据库而言,平时就值就是是TransactionDefinition.ISOLATION_READ_COMMITTED。Mysql默认repeatable
    read。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个业务可以读取另一个业务修改只是尚没有提交的数量。该级别不克防范脏读和不足再读或幻读,因而很少使该隔离级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事情只好读取另一个政工都交由的数量。该级别能够避免污染读,这为是大部分处境下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个工作在总体经过中得多次重复执行有查询,并且每趟回的记录还无异,因为他锁定了操作的举办。该级别可以预防脏读和不足再读,但幻读仍发生或产生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事体逐项逐个执行,这样工作间就净不容许发生烦扰,也就是说,该级别能够防污染读、不可再读与幻读。不过及时将重影响程序的性能。平常情状下为未汇合就此到拖欠级别。

单念属性

  事务的一味念属性是恃,对事务性资源拓展单独读操作如故是读写操作。所谓事务性资源就是据那几个给事务管理的资源,比如数据源、
JMS
资源,以及由定义之事务性资源等等。假设确定只对事务性资源开展单独念操作,那么我们好拿事情标志也特念之,以增长事务处理的性能。在
TransactionDefinition 中坐 boolean 类型来代表该业务是否只读。

作业超时

  所谓事务超时,就是负一个事务所允许实施的最丰硕日子,假使超越该日限定而事情还没水到渠成,则自动回滚事务。在
TransactionDefinition 中以 int 的价来表示过时间,其单位是秒。

工作之回滚规则

  日常情状下,即使当作业中丢掉来了无检查好(继承自Error类和
RuntimeException类的这个,其实只有待考虑
RuntimeException类非凡),则默认将回滚事务。假使无抛出任何特别,或者抛来了既检查好,则如故提交业务。这通常也是多数开发者希望的处理情势,也是
EJB
中之默认处理方式。可是,我们能够依据需要人工控制作业在抛出某些未检查大时依然提交业务,或者在抛出某些已检查大时回滚事务。

事情形态

  下边说到的调用PlatformTransactionManager接口的getTransaction()的主意赢得的凡TransactionStatus接口的一个实现,这么些接口的情节如下:

public interface TransactionStatus{
    boolean isNewTransaction(); // 是否是新的事物
    boolean hasSavepoint(); // 是否有恢复点
    void setRollbackOnly();  // 设置为只回滚
    boolean isRollbackOnly(); // 是否为只回滚
    boolean isCompleted; // 是否已完成
} 

  可以发现这一个接口描述的是片处理事务提供简的决定工作执行及查询业务状态的艺术,在回滚或交的下要使用对应之工作状态。

编程式事务

编程式和阐明式事务的分别

  Spring提供了对编程式事务与表明式事务的援助,编程式事务允许用户以代码中准确定义事务的境界,而声明式事务(基于AOP)有助于用户将操作与作业规则举办解耦。
简单地游说,编程式事务侵入到了事情代码里面,不过提供了越来越详细的事务管理;而注明式事务由因AOP,所以既然能起至事务管理的企图,又有何不可免影响工作代码的求实实现。

怎么着实现编程式事务

  Spring提供简单栽办法的编程式事务管理,分别是:使用TransactionTemplate和直接使用PlatformTransactionManager。

使用TransactionTemplate

  拔取TransactionTemplate和采取此外Spring模板,如JdbcTempalte和HibernateTemplate是平的形式。它使用回调方法,把应用程序从拍卖获与假释资源被脱身出来。如同其他模板,TransactionTemplate是线程安全之。代码有:

    TransactionTemplate tt = new TransactionTemplate(); // 新建一个TransactionTemplate
    Object result = tt.execute(
        new TransactionCallback(){  
            public Object doTransaction(TransactionStatus status){  
                updateOperation();  
                return resultOfUpdateOperation();  
            }  
    }); // 执行execute方法进行事务管理

  使用TransactionCallback()可以回来一个价。倘使运用TransactionCallbackWithoutResult则没有回值。

使用PlatformTransactionManager

        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); // 定义一个某个框架平台的TransactionManager,如JDBC、Hibernate
        dataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource()); // 设置数据源
        DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定义事务属性
        transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 设置传播行为属性
        TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef); // 获得事务状态
        try {
            // 数据库操作
            dataSourceTransactionManager.commit(status);// 提交
        } catch (Exception e) {
            dataSourceTransactionManager.rollback(status);// 回滚
        }

表明式事务

  Spring 的声明式事务管理在脚是创设于 AOP
的根底之上的。其真相是对章程前后开展阻拦,然后在目的措施起初从前成立或者出席一个政工,在推行了目的措施之后遵照实施意况提交或者回滚事务。
  阐明式事务最特别之长就是是匪欲经编程的艺术管理事务,这样固然不需要在工作逻辑代码中夹事务管理的代码,只待在部署文件被开相关的政工规则表明(或经当的基于注明的办法),便好用工作规则下至业务逻辑中。因为事务管理本身便是一个压倒元白的横切逻辑,正是
AOP 的用武之地。Spring
开发协会为发现及了即或多或少,为声明式事务提供了简便易行而有力的支撑。
  日常状态下,强烈提出在开被运用讲明式事务,不仅归因于这简单,更着重是为这么让纯业务代码不深受污染,极大方便前期的代码维护,相当契合
非侵入式轻量级容器的见识

  和编程式事务比较,声明式事务唯一不足地方是,后者的极致密切粒度只可以效用及方法级别,不可能就像编程式事务这样好功效及代码片级别。不过就是有诸如此类的急需,也设有不少变型之方法,比如,能够以需要开展事务管理的代码块独立为计等等。
  表明式事务管理也时有爆发点儿栽常用的章程,一种植是基于tx和aop名字空间的xml配置文件,另一样栽不畏是因@Transactional注。显著基于阐明的措施还简单容易用,更舒服。推荐以全讲明的安排模式:
spring-dao.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置整合mybatis过程
    1.配置数据库相关参数-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--2.数据库连接池-->
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <!--配置连接池属性-->
        <property name="driverClassName" value="${jdbc.driverClassName}" />

        <!-- 基本属性 url、user、password -->
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />

        <property name="maximumPoolSize" value="50"/>
        <property name="minimumIdle" value="10"/>
        <!--关闭连接后不自动commit-->
        <property name="autoCommit" value="false"/>

        <!-- 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒 -->
        <property name="connectionTimeout" value="1000"/>
        <!-- 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟 -->
        <property name="idleTimeout" value="1000" />
    </bean>

    <!--约定大于配置-->
    <!--3.配置SqlSessionFactory对象-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--往下才是mybatis和spring真正整合的配置-->
        <!--注入数据库连接池-->
        <property name="dataSource" ref="dataSource"/>
        <!--配置mybatis全局配置文件:mybatis-config.xml-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--扫描entity包,使用别名,多个用;隔开-->
        <property name="typeAliasesPackage" value="com.seckill.model"/>
        <!--扫描sql配置文件:mapper需要的xml文件-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

    <!--4:配置扫描Dao接口包,动态实现DAO接口,注入到spring容器-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--注入SqlSessionFactory-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 给出需要扫描的Dao接口-->
        <property name="basePackage" value="com.seckill.dao"/>
    </bean>
</beans>

spring-service.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--扫描service包下所有使用注解的类型-->
    <context:component-scan base-package="com.seckill.service"/>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据库连接池-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--配置基于注解的声明式事务
    默认使用注解来管理事务行为-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

这时候以DAO上欲加上@Transactional注解,如下:

    /**
     * 1.添加事务注解
     * 使用propagation 指定事务的传播行为,即当前的事务方法被另外一个事务方法调用时如何使用事务,默认取值为REQUIRED,即使用调用方法的事务
     * REQUIRES_NEW:使用自己的事务,调用的事务方法的事务被挂起。
     *
     * 2.使用isolation 指定事务的隔离级别,最常用的取值为READ_COMMITTED,但Mysql默认是REPEATABLE_READ。
     * 3.默认情况下 Spring 的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置。通常情况下,默认值即可。
     * 4.使用readOnly 指定事务是否为只读。 表示这个事务只读取数据但不更新数据,这样可以帮助数据库引擎优化事务。若真的是一个只读取数据库值得方法,应设置readOnly=true
     * 5.使用timeOut 指定强制回滚之前事务可以占用的时间。
     */
    @Transactional(propagation=Propagation.REQUIRES_NEW,
            isolation=Isolation.READ_COMMITTED,
            noRollbackFor={UserAccountException.class},
            readOnly=true, timeout=3)
@Component("userDao")
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

    public List<User> listUsers() {
        return this.getSession().createQuery("from User").list();
    }  
}

@Transactional注解

@Transactional属性

属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

用法

  @Transactional足功能为接口、接口方法、类和近似措施及。当功用为类及平日,该类的具备
public
方法以还装有该型的业务属性,同时,我们也可以在点子级别下该标注来覆盖类级别之概念。
  虽然 @Transactional
注脚可以功能被接口、接口方法、类及近似模式齐,不过 Spring
提出并非当接口或者接口方法及以该表明,因为就唯有在用基于接口的代办时其才会立竿见影。此外,
@Transactional注应该仅仅为接纳到 public 方法上,那是由 Spring AOP
的实质决定的。如若您于 protected、private 或者默认同见性的艺术上运
@Transactional注,这将吃忽略,也非相会弃来另非凡。
  默认情况下,只有来自外部的法门调用才会受AOP代理捕获,也不怕是,类里方法调用本类内部的别格局并无会合挑起事务行为,即便受调用方法运用@Transactional注举行修饰。

网站地图xml地图