zoukankan      html  css  js  c++  java
  • Spring 事务

    Spring 事务

    关于理论性的内容,我在之前的一篇文章中介绍过,这里不再过多阐述,这里给出之前文章的链接:Spring 事务管理

    什么是事务

    是一组逻辑操作,要么执行,要么不执行。

    事务的特性

    ACID
    (原子性、一致性、隔离性、持久性)

    并发事务带来的问题

    • 脏读
    • 丢失修改
    • 不可重复读
    • 幻读

    配置事务管理器

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

    Spring 事务接口

    • PlatformTransactionManager:(平台)事务管理器
    • TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)
    • TransactionStatus: 事务运行状态
    1. PlatfromTransactionManager 接口介绍:

    该接口主要有三个方法:

    Public interface PlatformTransactionManager()...{
    
        TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
    
        Void commit(TransactionStatus status) throws TransactionException;  
    
        Void rollback(TransactionStatus status) throws TransactionException;  
    } 
    
    • getTransaction:根据指定的传播行为,返回当前活动的事务或创建一个新事务
    • commit:使用事务目前的状态提交事务
    • rollback:对执行的事务进行回滚

    一般情况下用的比较多的就是 commit 提交事务和 rollback 回滚事操作了。

    2. TransactiDefinition 接口介绍:

    该接口主要定义了一些表示事务属性(如隔离级别,传播行为等)的常量。当然还有一些方法,仅有篇幅,不对方法做介绍。

    (1)事务隔离级别(定义了一个事务可能受其他并发事务影响的程度):

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

    • TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别。Mysql 默认采用 REPEATALBE-READ 隔离级别;Oracle 默认采用 READ_COMMITTED 隔离级别。
    • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
    • TransactionDefinition.ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
    • TransactionDefinition.ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
    • TransactionDefinition.ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
    (2)事务传播行为(为了解决业务层方法之间互相调用的事务问题):

    当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

    支持当前事务的情况:

    • TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
    • TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

    不支持当前事务的情况:

    • TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    • TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

    其他情况:

    • TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
    (3)TransactionStatus 接口介绍

    TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。
    TransactionStatus 接口方法如下:

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

    举例

    事务操作一般都是在 service 层编写,结合增删改查方法。我举个栗子:

    class Test {
        
        private PlatformTransactionManager transactionManager;
        
        public void saveFromDB() {
    
        	DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
        	defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        	TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
    
        	try {      
            	// 增删改查操作(使用 dao 中的方法)
            	//...
            	transactionManager.commit(transactionStatus);
            
            	// 删除本地缓存操作
            	//...
            
        	} catch (Exception e) {
            	transactionManager.rollback(transactionStatus);
            
        	}
    	}
    }
    

    这里需要注意的是:当我们执行增删查改操作时,应该在 service 层添加事务,并且删除之前的缓存(本地缓存和 redis 缓存),然后再执行增删查改操作,这三方面都兼顾到了才是一个比较好的增删查改操作。

    参考

    https://juejin.im/post/5b00c52ef265da0b95276091

  • 相关阅读:
    macOS 终端可用的 Hex 查看与编辑器
    MAC brew install 跳过 update
    zstd
    JAVA中的时区设置
    conda虚拟环境中设置环境变量
    vertx 获取请求参数
    idea2020.3激活码最新破解教程(亲测有效)
    Camtasia recorder 的快捷键
    ARM STM32 各种缩写和全称
    如何解决keil mdk中文汉字乱码或设置编码问题
  • 原文地址:https://www.cnblogs.com/weixuqin/p/11374069.html
Copyright © 2011-2022 走看看