Fork me on GitHub

【Spring】事务

一、数据库事务概述

  • 事务:是逻辑上一组操作,要么全都成功,要么全都失败.
  • 事务特性: (ACID)

    • 原子性:事务不可分割
    • 一致性:事务执行的前后,数据完整性保持一致.
    • 隔离性:一个事务执行的时候,不应该受到其他事务的打扰
    • 持久性:一旦结束,数据就永久的保存到数据库.
  • 如果不考虑隔离性会出现如下问题:

    • 脏读:一个事务读到另一个事务未提交数据
    • 不可重复读:一个事务读到另一个事务已经提交数据(update)导致一个事务多次查询结果不一致
    • 虚读:一个事务读到另一个事务已经提交数据(insert)导致一个事务多次查询结果不一致
  • 事务的隔离级别:

    • 未提交读:以上情况都有可能发生。
    • 已提交读:避免脏读,但不可重复读,虚读是有可能发生。
    • 可重复读:避免脏读,不可重复读,但是虚读有可能发生。
    • 串行的:避免以上所有情况.

    关于事务的详细内容可以查阅:【DataBase】事务

二、Spring中事务

1. Spring 事务管理:

  分层开发:事务处在Service层.

2. Spring 事务管理的API:

2.1 API概述

  1. PlatformTransactionManager:平台事务管理器,定义了如下方法:

    Public interface PlatformTransactionManager()...{  
        // Return a currently active transaction or create a new one, according to the specified propagation behavior(根据指定的传播行为,返回当前活动的事务或创建一个新事务。)
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    // Commit the given transaction, with regard to its status(使用事务目前的状态提交事务)
    Void commit(TransactionStatus status) throws TransactionException;
    // Perform a rollback of the given transaction(对执行的事务进行回滚)
    Void rollback(TransactionStatus status) throws TransactionException;
    }
  2. TransactionDefinition:事务定义信息

    • ISOLation_XXX:事务隔离级别
    • PROPAGATION_XXX:事务的传播行为
    • 过期时间等
  3. TransactionStatus:事务的状态

    • 是否有保存点
    • 是否一个新的事务
    • 事务是否已经提交
  • 上述接口之间的关系 PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务,管理事务过程中,产生一些事务状态:状态由TransactionStatus记录.

2.2 PlatformTransactionManager 接口

Spring为不同的持久化框架提供了不同PlatformTransactionManager接口实现 :

  1. org.springframework.jdbc.datasource.DataSourceTransactionManager:使用Spring JDBCMybatis 进行持久化数据时使用
  2. org.springframework.orm.hibernate3.HibernateTransactionManager :使用Hibernate3.0版本进行持久化数据时使用
  3. org.springframework.orm.jpa.JpaTransactionManager:使用JPA进行持久化时使用
  4. org.springframework.jdo.JdoTransactionManager:当持久化机制是Jdo时使用
  5. org.springframework.transaction.jta.JtaTransactionManager:使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用

如果我们在使用JDBC或者Mybatis进行数据持久化操作时,我们的XML配置通常如下:

<!-- 事务管理器 -->
    <bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
    <property name="dataSource" ref="dataSource" />
</bean>

2.3 TransactionDefinition 接口

  事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition类 ,
  这个类就定义了一些基本的事务属性。(隔离级别传播行为回滚规则是否只读事务超时

public interface TransactionDefinition {

//传播行为
    int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;

//隔离级别
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
    
    int TIMEOUT_DEFAULT = -1;
    
//方法
    int getPropagationBehavior();   
    int getIsolationLevel();
    int getTimeout();
    boolean isReadOnly();   
    String getName();
}
(1) 隔离级别 

  
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
 

  • ISOLATION_DEFAULT:默认的隔离级别. MySQL:repeatable_read ,Oracle: read_commited

  • ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读幻读不可重复读

  • ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读不可重复读仍有可能发生

  • ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生

  • ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

(2) 事务的传播行为

  
事务的传播行为:不是JDBC事务管理,是用来解决实际开发的问题,解决业务层之间的调用的事务的关系.
 

支持当前事务

  • ⭐️PROPAGATION_REQUIRED支持当前事务,如果不存在 就新建一个
    • A,B 如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A,B是在一个事务中。)
  • PROPAGATION_SUPPORTS支持当前事务,如果不存在,就不使用事务
    • A,B 如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务.
  • PROPAGATION_MANDATORY支持当前事务,如果不存在,抛出异常
    • A,B 如果A有事务,B使用A的事务,如果A没有事务,抛出异常.

不支持当前事务

  • ⭐️PROPAGATION_REQUIRES_NEW不支持当前事务,如果有事务存在,挂起当前事务,创建一个新的事务
    • A,B 如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中.事务互不影响.)
  • PROPAGATION_NOT_SUPPORTED不支持当前事务,以非事务方式运行,如果有事务存在,挂起当前事务
    • A,B 非事务的方式运行,A有事务,就会挂起当前的事务.
  • PROPAGATION_NEVER不支持当前事务,以非事务方式运行,如果有事务存在,抛出异常

其他(Spring 所特有的)

  • ⭐️PROPAGATION_NESTED:如果当前事务存在,则嵌套事务执行
    • 基于SavePoint技术.
      • A,B A有事务,A执行之后,将A事务执行之后的内容保存到SavePoint.B事务有异常的话,用户需要自己设置事务提交还是回滚.
(3) 事务超时属性(一个事务允许执行的最长时间)

 所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。
  

(4) 事务只读(对事物资源是否执行只读操作)

  事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。

(5) 回滚规则(定义事务回滚规则)

  这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)。但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

2.4 TransactionStatus 接口

  TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息.
  PlatformTransactionManager.getTransaction(…) 方法返回一个TransactionStatus 对象。返回的TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。TransactionStatus接口接口内容如下:

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

三、Spring 事务实战

声明式事务编程式事务

【Spring】编程式事务和声明式事务

posted @ 2019-08-13 04:10  这个世界~  阅读(456)  评论(0编辑  收藏  举报