【Spring 事务】【一】 Spring 事务简介

1  前言

本节我们开始来看看 Spring 事务哈,大家看之前首先要看过 IOC、AOP、甚至代理哈,如果这些你不知道原理,你看任何东西都会很费劲,比如Bean的生命周期、AOP的切入时机、什么时候创建代理以及执行时机,这些不知道的话,你就看事务的话,会很懵,当然前提是大家是带着思考看的哈,单纯看不思考的话当我没说哈...,所以前置的原理知识很重要。那么对于事务我们要看哪些呢?事务的启动时机,也就是自动装配的入口,事务我们也都知道是基于AOP,那么它的筛选标准是什么呢,也就是要给什么样的类或者方法创建代理呢?以及代理后实际控制事务、执行事务以及夹杂着传播机制、隔离级别的实现逻辑是怎么样的呢?这些就是我们要看的哈。本节只是开篇,我们先看看事务的一些基本知识概念,做个开头,下节我们看源码哈。

2  事务

2.1  什么是事务?

事务是指逻辑上的一组操作,这组操作要么全部成功,要么全部失败。

2.2  事务的特性

(1)原子性:指事务的操作要么全部都发生,要么都不发生。

(2)一致性:指事务执行前后数据的完整性必须保持一致。

(3)隔离性:指多个事务并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离(可以通过设置事务的隔离级别解决)。

(4)持久性:指一个事务一旦被提交,它对数据库中的数据的改变是永久性的,即使数据库发生故障也不应该对其有任何影响。

事务的原子性、一致性和持久性是通过数据库的redo/undo日志文件实现的。redo log处理系统故障,undo log处理事务回滚。如果在事务提交之后出现数据库崩溃(断电)的情况,在恢复供电时,数据库会根据重写日志对数据进行前滚。

2.3  事务带来的问题

(1)脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

(2)不可重复读:不可重复读是指一个事务对同一行数据执行了两次或更多次查询,但是却得到了不同的结果。

(3)幻读:幻读和不可重复读有点像,两者都表现为两次读取的结果不一致,只是针对的不是数据的值而是数据的数量。不可重复读重点在于update和delete,而幻读的重点在于insert。

2.4  Spring 事务

在Spring中,事务有两种实现方式,分别是编程式事务和声明式事务。

  • 编程式事务:编程式事务管理使用Transaction Template或者直接使用底层的PlatformTransactionManager。对于编程式事务,Spring推荐使用TransactionTemplate。TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  • 声明式事务:声明式事务基于AOP,其本质是对方法前后进行拦截,在方法开始前创建或加入一个事务,再根据目标方法执行的结果决定提交还是回滚事务。只需要在类、方法加上@Transactional注解就可以使用事务,没有入侵性,简单,也是我们接下来重点看的哈。

2.4.1  基础信息

Spring事务管理器高层抽象接口主要有3个接口:

(1)PlatformTransactionManager(平台事务管理器):主要是进行事务的提交回滚等功能。

  根据不同的持久化框架提供了不同的PlatformTransactionManager接口实现比如:

    • 使用Spring JDBC或iBatis:org.springframework.jdbc.datasource.DataSourceTransactionManager
    • 使用Hibernate3.0版本:org.springframework.orm.hibernate3.0.HibernateTransactionManager

(2)TransactionDefinition(事务定义信息):主要包含事务的隔离级别、传播行为、是否超时等。

(3)TransactionStatus(事务具体运行状态):包括事务是否已提交、是否是新创建的事务、是否有保存点等。

2.4.2  TransactionDefinition接口

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。比如使用MySQL默认就是 ISOLATION_REPEATABLE_READ,使用Oracle、PostageSQL默认就是 ISOLATION_READ_COMMITTED
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

  • 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。

2.4.3  声明式事务的常用配置

参 数 名 称

功 能 描 述

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:指定单一异常类名称@Transactional(rollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})

propagation

该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

tip:声明式事务@Transactional可以作用于接口、接口方法、类、类方法上,当作用到类时,该类下所有public方法都将具有该类型的事务属性,同时,也可以在方法级别使用该注解来覆盖类级别的定义。Spring的建议是在具体的实现类和类方法使用@Transactional注解,而不是使用在接口上。因为注解不能继承,不能被基于接口的代理类所识别,注解失效。

找了一个图,梳理一下:

3  小结

好了,关于事务的一些概念和基础配置我们就先看到这里哈,有理解不对的地方欢迎指正哈。

posted @ 2023-05-12 10:45  酷酷-  阅读(80)  评论(0编辑  收藏  举报