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

    事务的基本原理

    Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交,那在没有Spring帮我们管理事务之前,我们要怎么做。

    Connection conn = DriverManager.getConnection();
    try {  
        conn.setAutoCommit(false);  //将自动提交设置为false                         
        执行CRUD操作 
        conn.commit();      //当两个操作成功后手动提交  
    } catch (Exception e) {  
        conn.rollback();    //一旦其中一个操作出错都将回滚,所有操作都不成功
        e.printStackTrace();  
    } finally {
        conn.colse();
    }

    事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了确保数据的完整性和一致性,在目前企业级应用开发中,事务管理是必不可少的。

    与事务相关的理论知识

    众所周知,事务有四大特性(ACID)

    1.原子性(Atomicity)事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。

    2.一致性(Consistency)事务在完成时,必须是所有的数据都保持一致状态。

    3.隔离性(Isolation)并发事务执行之间无影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性。

    4.持久性(Durability)一旦事务完成,数据库的改变必须是持久化的。

    在企业级应用中,多用户访问数据库是常见的场景,这就是所谓的事务的并发。事务并发所可能存在的问题: 
    1.脏读:一个事务读到另一个事务未提交的更新数据。 
    2.不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。 
    3.幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。 
    4.丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。

    翻译过来这几个常量就是 
    TRANSACTION_NONE JDBC 驱动不支持事务 
    TRANSACTION_READ_UNCOMMITTED 允许脏读、不可重复读和幻读。 
    TRANSACTION_READ_COMMITTED 禁止脏读,但允许不可重复读和幻读。 
    TRANSACTION_REPEATABLE_READ 禁止脏读和不可重复读,单运行幻读。 
    TRANSACTION_SERIALIZABLE 禁止脏读、不可重复读和幻读。

    隔离级别越高,意味着数据库事务并发执行性能越差,能处理的操作就越少。你可以通过conn.setTransactionLevel去设置你需要的隔离级别。 
    JDBC规范虽然定义了事务的以上支持行为,但是各个JDBC驱动,数据库厂商对事务的支持程度可能各不相同。 
    出于性能的考虑我们一般设置TRANSACTION_READ_COMMITTED就差不多了,剩下的通过使用数据库的锁来帮我们处理别的,关于数据库的锁这个之后再说。

    了解了基本的JDBC事务,那有了Spring,在事务管理上会有什么新的改变呢? 
    有了Spring,我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作,使得我们把更多的精力放在处理业务上。事实上Spring并不直接管理事务,而是提供了多种事务管理器。他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。

    Spring事务管理

    Spring事务管理的核心接口是PlatformTransactionManager 

    Spring事务的传播属性

    由上图可知,Spring定义了7个以PROPAGATION_开头的常量表示它的传播属性。

    名称解释
    PROPAGATION_REQUIRED 0 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是Spring默认的事务的传播。
    PROPAGATION_SUPPORTS 1 支持当前事务,如果当前没有事务,就以非事务方式执行。
    PROPAGATION_MANDATORY 2 支持当前事务,如果当前没有事务,就抛出异常。
    PROPAGATION_REQUIRES_NEW 3 新建事务,如果当前存在事务,把当前事务挂起。
    PROPAGATION_NOT_SUPPORTED 4 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    PROPAGATION_NEVER 5 以非事务方式执行,如果当前存在事务,则抛出异常。
    PROPAGATION_NESTED 6 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

    Spring事务的隔离级别

    名称解释
    ISOLATION_DEFAULT -1 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应
    ISOLATION_READ_UNCOMMITTED 1 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻读。
    ISOLATION_READ_COMMITTED 2 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
    ISOLATION_REPEATABLE_READ 4 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻读。
    ISOLATION_SERIALIZABLE 8 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。

    配置事务管理器

    介绍完Spring事务的管理的流程大概是怎么走的。接下来可以动手试试Spring是如何配置事务管理器的 
    例如我在spring-mybatis中配置的:

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

    这配置不是唯一的,可以根据自己项目选择的数据访问框架灵活配置事务管理器

    配置了事务管理器后,事务当然还是得我们自己去操作,Spring提供了两种事务管理的方式:编程式事务管理和声明式事务管理,让我们分别看看它们是怎么做的吧。

    声明式事务管理

    声明式事务管理有两种常用的方式,一种是基于tx和aop命名空间的xml配置文件,一种是基于@Transactional注解,随着Spring和Java的版本越来越高,大家越趋向于使用注解的方式,下面我们两个都说。 
    1.基于tx和aop命名空间的xml配置文件 
    配置文件

        <tx:advice id="advice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="insert" propagation="REQUIRED" read-only="false"  rollback-for="Exception"/>
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
            <aop:pointcut id="pointCut" expression="execution (* com.gray.service.*.*(..))"/>
            <aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
        </aop:config>

    2.基于@Transactional注解 
    这种方式最简单,也是最为常用的,只需要在配置文件中开启对注解事务管理的支持。

        <!-- 声明式事务管理 配置事物的注解方式注入-->
        <tx:annotation-driven transaction-manager="transactionManager"/>

    然后在需要事务管理的地方加上@Transactional注解,如:

        @Transactional(rollbackFor=Exception.class)
        public void insert(String sql, boolean flag) throws Exception {
            dao.insertSql(sql);
            // 如果flag 为 true ,抛出异常
            if (flag){
                throw new Exception("has exception!!!");
            }
        }

    rollbackFor属性指定出现Exception异常的时候回滚,遇到检查性的异常需要回滚,默认情况下非检查性异常,包括error也会自动回滚。 
    测试代码和上面那个一样 

    以上就是对Spring事务进行了详细的分析和代码示例。 
    最后是测试代码Spring事务测试

    参考:https://blog.csdn.net/donggua3694857/article/details/69858827

  • 相关阅读:
    CSS弹性盒布局(display:flex)
    CSS中的display属性(none,block,inline,inline-block,inherit)
    【Python全栈-JavaScript】JavaScript的window.onload()与jQuery 的ready()的区别
    【数据可视化-Echarts】Echart基础
    【Python全栈】HTML <!--...--> 注释 、CSS/JS //注释 和 /*.....*/ 注释
    Python内置函数
    【Django】Model操作进阶
    【Django】Form组件-2
    【Django】分页
    【Django】模板语言
  • 原文地址:https://www.cnblogs.com/xiaolovewei/p/9418874.html
Copyright © 2011-2022 走看看