Spring Boot事务管理(中)

在上一篇 Spring Boot事务管理(上)的基础上介绍Spring Boot事务属性和事务回滚规则 。

4 Spring Boot事务属性

什么是事务属性呢?事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面,如图所示,它们定义于TransactionDefinition接口类

  1、 事务隔离级别

隔离级别是指若干个并发事务之间的隔离程度。

Spring Boot的隔离级别被封装在枚举类Isolation,枚举值取自接口TransactionDefinition 定义,该接口中定义了五个表示隔离级别的常量:


隔离级别


含义


ISOLATION_DEFAULT


默认值,使用后端数据库默认的隔离级别


ISOLATION_READ_UNCOMMITTED


表示一个事务可以读取另一个事务修改但还没有提交的数据。可能导致脏读,不可重复读和幻读,因此很少使用该隔离级别。最低的隔离级别。


ISOLATION_READ_COMMITTED


表示一个事务只能读取另一个事务已经提交的数据。可以防止脏读,但是幻读或不可重复读仍有可能发生,这也是大多数情况下的推荐值。


ISOLATION_REPEATABLE_READ


表示一个事务在整个过程中可以多次重复执行某个查询并且每次返回的记录都相同。可以防止脏读和不可重复读,但幻读仍有可能发生。MySQL默认隔离级别。


ISOLATION_SERIALIZABLE


所有的事务依次逐个执行,事务之间完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能,因为它通常是通过完全锁定事务相关的数据库表来实现的。

    2、 事务传播规则

事务传播行为(propagation behavior)用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时候,事务如何传播。

传播行为定义了事务范围,何时触发事务,是否暂停现有事务,或者在调用方法是如果没有事务则失败等等。

Spring Boot的事务传播行为常量被封装在枚举类Propagation,枚举值取自接口TransactionDefinition,在接口中定义了如下七个表示传播行为的常量:


传播行为


含义


PROPAGATION_REQUIRED


如果当前存在事务,则加入该事务;否则,新建一个事务。这是默认值


PROPAGATION_REQUIRES_NEW


新建事务,如果当前存在事务,则挂起当前事务


PROPAGATION_SUPPORTS


如果当前存在事务,则加入该事务;否则,以非事务的方式继续运行


PROPAGATION_NOT_SUPPORTED


以非事务方式运行,如果当前存在事务,则挂起当前事务


PROPAGATION_NEVER


以非事务方式运行,如果当前存在事务,则抛异常


PROPAGATION_MANDATORY


如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常


PROPAGATION_NESTED


如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED

下面贴出TransactionDefinition中关于传播行为的源码。

    /**
     * Support a current transaction; create a new one if none exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p>This is typically the default setting of a transaction definition,
     * and typically defines a transaction synchronization scope.
     */
    int PROPAGATION_REQUIRED = 0;

    /**
     * Support a current transaction; execute non-transactionally if none exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> For transaction managers with transaction synchronization,
     * {@code PROPAGATION_SUPPORTS} is slightly different from no transaction
     * at all, as it defines a transaction scope that synchronization might apply to.
     * As a consequence, the same resources (a JDBC {@code Connection}, a
     * Hibernate {@code Session}, etc) will be shared for the entire specified
     * scope. Note that the exact behavior depends on the actual synchronization
     * configuration of the transaction manager!
     * <p>In general, use {@code PROPAGATION_SUPPORTS} with care! In particular, do
     * not rely on {@code PROPAGATION_REQUIRED} or {@code PROPAGATION_REQUIRES_NEW}
     * <i>within</i> a {@code PROPAGATION_SUPPORTS} scope (which may lead to
     * synchronization conflicts at runtime). If such nesting is unavoidable, make sure
     * to configure your transaction manager appropriately (typically switching to
     * "synchronization on actual transaction").
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
     */
    int PROPAGATION_SUPPORTS = 1;

    /**
     * Support a current transaction; throw an exception if no current transaction
     * exists. Analogous to the EJB transaction attribute of the same name.
     * <p>Note that transaction synchronization within a {@code PROPAGATION_MANDATORY}
     * scope will always be driven by the surrounding transaction.
     */
    int PROPAGATION_MANDATORY = 2;

    /**
     * Create a new transaction, suspending the current transaction if one exists.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * <p>A {@code PROPAGATION_REQUIRES_NEW} scope always defines its own
     * transaction synchronizations. Existing synchronizations will be suspended
     * and resumed appropriately.
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_REQUIRES_NEW = 3;

    /**
     * Do not support a current transaction; rather always execute non-transactionally.
     * Analogous to the EJB transaction attribute of the same name.
     * <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
     * on all transaction managers. This in particular applies to
     * {@link org.springframework.transaction.jta.JtaTransactionManager},
     * which requires the {@code javax.transaction.TransactionManager} to be
     * made available it to it (which is server-specific in standard Java EE).
     * <p>Note that transaction synchronization is <i>not</i> available within a
     * {@code PROPAGATION_NOT_SUPPORTED} scope. Existing synchronizations
     * will be suspended and resumed appropriately.
     * @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_NOT_SUPPORTED = 4;

    /**
     * Do not support a current transaction; throw an exception if a current transaction
     * exists. Analogous to the EJB transaction attribute of the same name.
     * <p>Note that transaction synchronization is <i>not</i> available within a
     * {@code PROPAGATION_NEVER} scope.
     */
    int PROPAGATION_NEVER = 5;

    /**
     * Execute within a nested transaction if a current transaction exists,
     * behave like {@link #PROPAGATION_REQUIRED} else. There is no analogous
     * feature in EJB.
     * <p><b>NOTE:</b> Actual creation of a nested transaction will only work on
     * specific transaction managers. Out of the box, this only applies to the JDBC
     * {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
     * when working on a JDBC 3.0 driver. Some JTA providers might support
     * nested transactions as well.
     * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
     */
    int PROPAGATION_NESTED = 6;

理解PROPAGATION_NESTED的关键是savepoint。他与REQUIRES_NEW的区别REQUIRES_NEW另起一个事务,将会与它的父事务相互独立,而Nested的事务和父事务是相依的,它的提交是要等待和父事务一块提交的。也就是说,如果父事务最后回滚,它也要回滚的;如果子事务回滚而且异常被捕获,父事务无感知,则父事务不回滚。

public class TransactionalDemo {

@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRES_NEW)

public void doSth() {

//        do something

}

}

    

3、 事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

    /**
     * Return the transaction timeout.
     * <p>Must return a number of seconds, or {@link #TIMEOUT_DEFAULT}.
     * <p>Only makes sense in combination with {@link #PROPAGATION_REQUIRED}
     * or {@link #PROPAGATION_REQUIRES_NEW}.
     * <p>Note that a transaction manager that does not support timeouts will throw
     * an exception when given any other timeout than {@link #TIMEOUT_DEFAULT}.
     * @return the transaction timeout
     */
    int getTimeout();

    4、 事务只读属性

只读事务用于只读取但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。默认为读写事务。

//@return {@code true} if the transaction is to be optimized as read-only
boolean isReadOnly();

    5、 事务回滚规则

指示Spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。Spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。默认配置下,Spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出哪些异常时回滚事务,包括checked异常。也可以明确定义哪些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

Spring的事务边界是在调用业务方法之前开始的,通过调用connection.setAutoCommit(false)激活事务,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常)以结束事务。如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception;否则,Spring会将你的操作commit,这样就会产生脏数据,所以你的catch代码是画蛇添足。如:

try {

// bisiness logic code

} catch(Exception e) {

// handle the exception

}

由此可以推知,在Spring中如果某个业务方法被一个try catch整个包裹起来,那么这个业务方法也就等于脱离了Spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致Spring异常抛出触发事务回滚策略失效。不过,如果在catch代码块中采用页面硬编码的方式使事务显式的回滚,这样写也未尝不可。

原文地址:https://www.cnblogs.com/east7/p/10585699.html

时间: 2024-10-09 01:42:01

Spring Boot事务管理(中)的相关文章

Spring Boot事务管理(下)

在上两篇 Spring Boot事务管理(上)和Spring Boot事务管理(中)的基础上介绍注解@Transactional. 5 @Transactional属性 属性 类型 描述 value String 指定使用的事务管理器 propagation enum: Propagation 可选的事务传播行为设置 isolation enum: Isolation 可选的事务隔离级别设置 readOnly boolean 读写或只读事务,默认读写 timeout int,unit secon

【Spring Boot学习之四】Spring Boot事务管理

环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 一.springboot整合事务事务分类:编程事务.声明事务(XML.注解),推荐使用注解方式,springboot默认集成事物,只主要在方法上加上@Transactional即可1.controller package com.wjy.controller; import org.springframework.beans.factory.annotation.Autowired; import org.spri

spring boot事务管理

spring boot集成事务十分的简单,只需要在启动类上面增加@EnableTransactionManagement注解,然后在需要实现事务的方法上添加@Transactional注解就可以了.下面我们根据上一次的代码来演示下. 首先,我们修改下启动类 package com.example.demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplicat

spring与事务管理

就我接触到的事务,使用最多的事务管理器是JDBC事务管理器.现在就记录下在spring中是如何使用JDBC事务管理器 1)在spring中配置事务管理器 <!-- JDBC事务 -->    <bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property

Spring初学之spring的事务管理xml

所有的java类都是用的上一篇文章:Spring初学之spring的事务管理 不同的是,这时xml配置事务,所以就要把java类中的那些关于spring的注解都删掉,然后在xml中配置,ApplicationContext.xml如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans&q

Spring的事务管理

事务 事务:是逻辑上一组操作,要么全都成功,要么全都失败. 事务特性(ACID) 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 隔离性:一个事务执行的时候,不应该受到其他事务的打扰 持久性:一旦结束,数据就永久的保存到数据库 如果不考虑隔离性 脏读:一个事务读到另一个事务未提交数据 不可重复读:一个事务读到另一个事务已经提交数据(update)导致一个事务多次查询结果不一致 虚读:一个事务读到另一个事务已经提交数据(insert)导致一个事务多次查询结果不一致 事务的隔离级别

spring笔记--事务管理之声明式事务

事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使用事务: 作为一个受欢迎的企业应用框架,Spring在不同的事务管理API上定义了一个抽象层,而开发时不必了解底层的事务管理API,就可以使用Spring的事务管理机制. Spring既支持编程式的事务管理,也支持声明式的事务管理,大多数情况我们选择后者. 编程式事务管理:将事务管理代码嵌入到业务代

Spring初学之spring的事务管理注解

spring的事务管理,本文的例子是:比如你需要网购一本书,卖书的那一方有库存量以及书的价格,你有账户余额.回想我们在编程中要实现买书这样的功能,由于你的账户表和书的库存量表肯定不是同一张数据库表,所以必定会有一个先后,要么先将账户余额扣除书的价格,紧接着将书的库存量减一,要么反过来.那么问题来了,假如我们先将你的账户余额减掉,然后发现书的库存不足,这时怎么办呢,这就需要事务了,当我们发现书的库存不足时就要回滚事务,将你的余额返回去.只要配置了事务,发生了异常,就回滚.这就是事务的回滚.注:新人

深入Spring:自定义事务管理

转自: http://www.jianshu.com/p/5347a462b3a5 前言 上一篇文章讲了Spring的Aop,这里讲一下Spring的事务管理,Spring的事务管理是建立在Aop的基础上的,相比Aop,事务管理的实现耦合性比较小,自定义就比较简单了. 自定义事务 Spring的开启事务管理主要是通过@EnableTransactionManagement注解来实现的.查看源码就会发现,这个注解主要是注入了两个类InfrastructureAdvisorAutoProxyCrea