• 作者:老汪软件技巧
  • 发表时间:2024-09-16 04:01
  • 浏览量:

一、前言

在我们日常学习和使用Spring框架的时候一定绕不开这样一个概念:Spring事务。其实,这里更准确的说法应该是Spring事务管理。为什么这里闲宇要特地强调“事务管理”而非单纯的“事务”呢?那是因为Spring框架本身并没有直接实现事务处理的能力,而是提供了一套基于Java标准的事务管理能力,实际的事务处理仍然需要开发者自身利用Spring提供的这一能力来去实现。也就是说,此“事务”并非彼“事务”。

为了更好地理解这两者的区别,下面让我们具体地去了解一下数据库系统中的事务和Spring中的事务管理到底是什么。

二、数据库系统中的事务

事务的概念最早诞生于数据库领域,特别是在关系型数据库发展的过程中。这一概念旨在解决数据在多步骤操作中的一致性、完整性和可靠性问题。简单来说,事务这一概念是用于数据操作过程的,脱离了数据操作,事务也就失去了意义。

1. 真实的事务

事务(Transaction) 是数据库系统中的一个重要概念,指的是一组操作或指令,它们作为一个整体被执行,要么全部执行成功,要么全部失败并回滚。在事务中,多个操作组合成一个原子性单元,确保数据的完整性和一致性。简单来说,事务就是无法被分割一组操作或者指令。

而要想实现上面概念中要求的内容,事务就必须具备以下特性,也就是我们经常听到的ACID特性:

这里闲宇需要特别提醒一下大家,有不少朋友在学习和使用事务的时候会错误地认为只有并发环境才需要事务,而在脱离了并发环境的情况下事务就变得可有可无了,这样的认知其实是错误的。从上面介绍的事务的核心特点中我们可以发现,只有隔离性谈到了并发环境的处理,其他三点并没有特别点出并发环境的这一条件。也就是说,在脱离了并发环境的情况下,对于正常的业务处理逻辑来说,其余三点依然是非常重要的。

其实这样的认知并不是难以理解,这里我们通过几个简单的场景来看一下为什么非并发环境依然需要事务。

2. 事务处理

事务处理实际上就是实现上述事务概念中提到的内容的操作或者机制,在我们使用的绝大部分数据库系统都实现了事务处理的能力。这里我们通过MySQL来看下数据库是如何提供事务处理能力的。

对于MySQL来说,事务处理由两种模式,分别是隐式事务控制和显式事务控制:

需要注意的是,在MySQL当中是否具备事务控制能力还与存储引擎有关,如果我们选择的MyISAM(不支持事务)则上述两种事务控制能力都不可用,每条SQL语句在执行后会,数据更改会立即生效,无法通过事务机制进行撤销或者回滚。而如果我们使用的是InnoDB则两种事务控制能力均可使用。

三、Spring中的事务管理

在看完了上面关于数据库系统中事务的介绍之后,相信大家已经能够发现两者的一些不同之处。事务本身就是应用于数据操作过程的,对于生而就是为了进行数据操作的数据库而言,事务处理可以说是一项非常基本的功能,这也是为什么绝大部分数据库都会提供事务这一能力。而对于Spring这种开发框架来说,数据操作过程完全依托于实际业务逻辑,同时这些数据究竟如何存储,存储到那种或者哪几种数据库当中这些都是不可预知的,这也就导致了让Spring去实现类似数据库当中事务处理成为了一种非常不现实的事情。

1. 基于业务逻辑的事务管理

由于实际的数据操作过程依赖业务逻辑,而业务逻辑由完全由开发者自身掌控,所以Spring选择将事务管理的权利交托给开发者自行掌控。也就是说Spring提供了一套显式创建事务、提交事务以及回滚事务的能力,即我们经常碰到的声明式事务和编程式事务。

需要注意的是,Spring虽然提供了事务管理能力,但其本身并没有事务处理能力,实际的事务处理仍需依赖数据库本身的事务处理能力。也就是说,看似你好像用Spring实现了一套事务管理能力,但是如果在你的方法内部没有操作数据库或者数据库本身并没有事务处理能力,那么你这一套事务管理逻辑也是没有任何用处的。

2. Spring事务管理的局限性

除了上面提到的问题,Spring的事务管理还存在另外一个非常头疼的问题:即在单一应用当中如果出现跨多个数据库(无论是同种类型或者不同种类型)的数据操作过程,此时声明式事务将无法保证事务的一致性,也就失去了它的作用。

这里我们需要先了解一下事务的两种类型:本地事务和全局事务。

@Transactional注解所管理的事务通常是针对单一数据库的本地事务,对于多数据库的场景显然是没有办法处理。因为不同的数据库各自有各自的事务边界,没有办法简单的通过一个@Transactional注解就能将其合并成一个。毕竟声明式事务实际的处理逻辑就是简单的利用本地事务在方法的开头添加“开启事务”指令,在方法的执行完成后发出“提交”指令,以及在检测到异常时发出“回滚”指令。

有人可能会说,声明式事务不起作用,那么编程式事务呢?确实,编程式事务由于提供了更细粒度的事务控制能力可以在一定程度上帮助开发者更好地控制事务的边界,但是它并不能直接解决全局事务中的一致性问题,要想解决这一个问题你就需要一种分布式事务协议来去保证。当然,这就是另外的价钱,哦,不,这就是另外的问题了,有机会我们以后再聊。

四、总结

在介绍了这么多之后,相比大家应该明白标题当中所说的此“事务”非彼“事务”的含义了。除了了解两者的区别,闲宇还和大家分析了一下Spring事务管理的局限性,当然如果系统本身不涉及全局事务的情况,我们还是可以放心的去使用Spring的事务管理能力,当然能不能用好那就是另外一个问题了[狗头]。

最后,祝大家身体健康,心想事成,早日财富自由~~