数据库事务概述
数据库事务是数据库管理系统(DBMS)中的一个关键概念,它涉及到一系列数据库操作,这些操作要么全部执行成功,要么全部不执行,以保持数据库的一致性。事务是确保数据库数据完整性和可靠性的基础。
事务是如何实现的
事务就是一组逻辑操作的集合。实现事务就是要保证可靠性和并发隔离,或者说,能够满足ACID特性的机制。而这些主要是靠日志恢复和并发控制实现的。
- 日志恢复:数据库里有两个日志,一个是redo log,一个是undo log。redo log记录的是已经成功提交的事务操作信息,用来恢复数据,保证事务的持久性。undo log记录的是事务修改之前的数据信息,用来回滚数据,保证事务的原子性。
- 并发控制:并发控制主要靠锁机制和MVCC(多版本并发控制)来实现,保证事务的隔离性。
- 一致性则是通过持久性+原子性+隔离性来保证。
事务的ACID特性
事务的状态
- 活动(Active): 事务进入活动状态表示它已经开始,但尚未完成。这是事务的起始状态。
- 部分提交(Partially Committed): 事务执行了所有的SQL语句,但尚未提交。在这个状态下,事务对数据库所做的修改已被写入事务日志,但尚未应用到数据库中。
- 已提交(Committed): 事务已经成功完成并已提交。在这个状态下,事务对数据库所做的修改已经永久保存在数据库中,成为数据库的一部分。
- 失败(Failed): 事务执行过程中发生了一个错误,导致事务无法继续执行。在这个状态下,通常会选择回滚事务,将数据库恢复到事务开始前的状态。
- 中止(Aborted): 事务被中止,可能是由于发生错误导致的回滚,也可能是由于应用程序显式地中止了事务。
- 挂起(Suspended): 事务处于一个暂时的挂起状态,等待某些条件满足后再继续执行。这通常与事务隔离级别相关,例如,在并发控制中等待其他事务释放锁。
这些状态反映了事务在其生命周期内可能经历的不同阶段。MySQL通过事务日志(transaction log)和锁来跟踪和管理事务的状态,以确保事务的ACID属性得到维护。了解事务的不同状态是非常重要的,以便在处理错误、调优性能或者确保数据一致性时能够采取适当的操作。
事务的使用
事务的完成过程:
- 手动启动: 明确地使用
START TRANSACTION
或者BEGIN
语句来显式地启动一个事务。这表示从这一点开始,所有的数据库操作将作为一个事务进行处理。 - 手动提交或回滚: 在事务执行结束后,需要明确地使用
COMMIT
提交事务,或者使用ROLLBACK
回滚事务。这使得开发者有更精确的控制,可以根据业务逻辑决定是否提交或回滚事务。
- 自动启动: 在默认情况下,每个SQL语句都被视为一个事务。这意味着在执行SQL语句时,会自动启动一个事务。
- 自动提交: 在隐式事务中,每个SQL语句执行后都会自动提交事务,除非显式地使用
SET AUTOCOMMIT=0
关闭自动提交,这时需要使用COMMIT
或ROLLBACK
手动处理事务。
显式事务
1.开启事务
使用START TRANSACTION
或者 BEGIN
开启一个事务。
START TRANSACTION;
BEGIN;
START TRANSACTION
语句相较于 BEGIN
特别之处在于,后边能跟随几个 修饰符 :
2.一系列事务中的操作
3.提交事务或者中止事务
# 提交事务。当提交事务后,对数据库的修改是永久性的。
COMMIT;
# 回滚事务。即撤销正在进行的所有没有提交的修改
ROLLBACK;
# 将事务回滚到某个保存点。
ROLLBACK TO [SAVEPOINT]
保存点
# 创建保存点
SAVEPOINT 保存点名称;
# 删除保存点
RELEASE SAVEPOINT 保存点名称;
隐式事务
MySQL中有一个系统变量 autocommit
:默认是ON,也就是开启自动事务。
关闭自动提交:
- 显式的的使用
START TRANSACTION
或者BEGIN
语句开启一个事务。这样在本次事务提交或者回 滚前会暂时关闭掉自动提交的功能。 - 把系统变量
autocommit
的值设置为OFF
,就像这样:
SET autocommit = OFF;
#或
SET autocommit = 0;
示例
自动提交
关闭自动提交后,可以多条语句为一个事务。
回滚
回滚,回滚后数据回到开启事务前的状态。
回滚到保存点
回滚到保存点
需要注意的是,回滚到保存点并不是事务的终止状态,所以不会提交事务
事务的隔离级别
数据并发问题
脏读
:指一个事务读取到了另一个事务修改但是还没有提交的数据,如果另一个事务后来回滚了,读取到的数据就是无效的,导致事务读取到的数据是“脏”的,因为它基于未提交的数据。
比如A向B转账100,A的账户减少了100,而B的账户还没来得及修改,此时一个并发的事务访问到了B的账户,就是脏读
不可重复读
:指一个事务多次读取同一条记录,但前后读到的数据不一致。因为当前事务在读取记录的间隙中,其他事务在此期间修改或删除了数据并进行了提交, 这可能导致事务在执行期间看到不一致的数据,破坏了事务的一致性。
比如A第一次查询自己的账户有100元,此时另一个事务给A的账户增加了100元,所以A再次读取他的账户得到了200的结果,跟第一次读取的不一样。
不可重复读与脏读的不同之处在于,脏读是读取了另一个事务没有提交的脏数据,不可重复读是读取了已经提交的数据,实际上并不是一个异常现象。
幻读
:事务在查询特定记录的总数时,前后查询的结果不一致。这是由于在事务查询间隙时,在此期间插入了新的数据。 这可能导致事务在执行期间看到不一致的数据,破坏了事务的一致性。
比如A公司一共有100个人,第一次查询总人数得到100条记录,此时另一个事务新增了一个人,所以下一次查询得到101条记录。
不可重复度和幻读的不同之处在于,幻读是多次读取的结果行数不同,不可重复度是读取结果的值不同。
MySQL 支持的四种隔离级别
READ UNCOMMITTED
:读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结 果。不能避免脏读、不可重复读、幻读。
READ COMMITTED
:读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做 的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可 重复读、幻读问题仍然存在。
REPEATABLE READ
:可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提 交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍 然存在。这是MySQL的默认隔离级别。
SERIALIZABLE
:可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止 其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避 免脏读、不可重复读和幻读。
- 对于「读未提交」隔离级别的事务来说,因为可以读到未提交事务修改的数据,所以直接读取最新的数据就好了;
- 对于「串行化」隔离级别的事务来说,通过加读写锁的方式来避免并行访问;
- 对于「读提交」和「可重复读」隔离级别的事务来说,它们是通过 Read View 来实现的,它们的区别在于创建 Read View 的时机不同,大家可以把 Read View 理解成一个数据快照,就像相机拍照那样,定格某一时刻的风景。「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 Read View,而「可重复读」隔离级别是「启动事务时」生成一个 Read View,然后整个事务期间都在用这个 Read View。
注意
MySQL 虽然支持 4 种隔离级别,但是与SQL 标准中规定的各级隔离级别允许发生的现象却有些出入。
MySQL 在「可重复读」隔离级别下,可以很大程度上避免幻读现象的发生(注意是很大程度避免,并不是彻底避免),所以 MySQL 并不会使用「串行化」隔离级别来避免幻读现象的发生,因为使用「串行化」隔离级别会影响性能。
MySQL InnoDB 引擎的可重复读隔离级别(默认隔离级),根据不同的查询方式,分别提出了避免幻读的方案:
- 针对快照读(普通 select 语句),是通过 MVCC 方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
- 针对当前读(select … for update 等语句),是通过 next–key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select … for update 语句的时候,会加上 next–key lock,如果有其他事务在 next–key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
示例
其他事务增加数据后,当前事务的查询结果并不会改变。
但是,虽然当前事务查询不到,但是能够修改且修改后就能查询到。
所以MySQL 在「可重复读」隔离级别下,可以很大程度上避免幻读现象的发生但不能彻底避免。
设置隔离级别
SELECT @@transaction_isolation;
设置隔离级别
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别;
#其中,隔离级别格式:
> READ UNCOMMITTED
> READ COMMITTED
> REPEATABLE READ
> SERIALIZABLE
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'
#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE
# SET SESSION TRANSACTION_ISOLATION = '隔离级别' == SET TRANSACTION_ISOLATION = '隔离级别'
关于设置时使用GLOBAL或SESSION的影响:(默认 SESSION )
事务的常见分类
- 扁平事务(Flat Transactions):
- 带有保存点的扁平事务(Flat Transactions with Savepoints):
- 链事务(Chained Transactions):
- 嵌套事务(Nested Transactions):
- 分布式事务(Distributed Transactions):
原文地址:https://blog.csdn.net/zxwyhzy/article/details/134652230
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_13829.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!