前言
在数据库操作的复杂世界里,事务是保障数据一致性、完整性和可靠性的关键机制。
无论是银行系统中的资金转账,还是电商平台的订单处理,事务都在默默地发挥着重要作用。MySQL 作为广泛使用的数据库管理系统,其事务处理机制涉及到多个重要的概念和特性。从原子性确保操作的整体性,到一致性维护数据在事务前后的稳定状态,再到隔离性控制并发事务之间的相互影响,以及持久性保障提交后数据的安全存储,每一个特性都值得深入探究。
同时,事务的隔离级别和保存点等相关内容也对数据库操作的准确性和灵活性有着重要意义。
本文将详细剖析 MySQL 事务的相关知识,包括其基本概念、特性、操作命令、隔离级别以及保存点等内容,并通过实例演示不同隔离级别下的行为,帮助读者更好地理解和运用 MySQL 事务。
ok,那么我们开始。
目录
一. 什么是事务
事务是一组数据库操作的逻辑单元,这些操作要么全部成功执行,要么全部不执行。在 MySQL 中,事务可以保证数据库的一致性和完整性。就好像是一个 “包裹”,里面装着一系列的数据库操作指令,这些指令被当作一个整体来对待。
当一个事务里面所有操作全部执行成功后,该事务才会提交,某条sql语句一旦执行失败或者产生错误,那么整个单元将会回滚(返回最初状态),从而达到数据安全的效果。
众说周知,mysql使用不同的存储引擎来存储数据的,常用引擎有innodb、myisam,memory等,其中只有innodb支持事务操作,这也是我们使用innodb引擎的原因之一。
二. 事物的特性
1.原子性
原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。例如,在一个银行转账系统中,从账户 A 转账 100 元到账户 B,这个事务包含两个操作:从账户 A 扣除 100 元,在账户 B 增加 100 元。这两个操作必须作为一个整体来执行,不能出现只扣除了账户 A 的钱,而账户 B 没有增加钱的情况。如果在执行过程中出现任何错误,整个事务就会回滚,回到事务开始之前的状态。
2. 一致性
事务必须使数据库从一个一致性状态变换到另一个一致性状态。也就是说,事务执行前后,数据库的完整性约束没有被破坏。继续以银行转账为例,在转账事务执行前后,整个银行系统的资金总额是不变的,这就是保持了一致性。如果转账前银行系统的总资金是 10000 元,那么转账成功后总资金仍然应该是 10000 元,只是资金在不同账户之间的分配发生了变化。
3. 隔离性
多个事务并发执行时,一个事务的执行不能被其他事务干扰。每个事务都感觉不到其他事务在并发地执行。例如,有两个用户同时进行转账操作,用户 1 从账户 A 转账到账户 B,用户 2 从账户 C 转账到账户 D。这两个转账事务应该相互独立,互不干扰。隔离性可以通过设置不同的隔离级别来控制事务之间的相互影响程度。
3.1. 并发问题
1.脏读
脏读是指一个事务读取了另一个未提交事务的数据。由于未提交事务的数据可能会在后续操作中被回滚,所以读取到的数据可能是不正确的。
假设有两个事务,事务 A 和事务 B。事务 A 正在修改一条记录,将某个账户的余额从 1000 元修改为 1200 元,但尚未提交。此时事务 B 读取了该账户余额,得到 1200 元。随后事务 A 由于某种原因回滚,账户余额恢复到 1000 元。事务 B 读取到的 1200 元就是脏数据,这种情况就是脏读。
2.不可重复读
一个事务在对同一数据进行多次读取操作的过程中,由于其他事务对该数据进行了修改或删除操作,导致该事务每次读取到的数据都不同。这种情况主要是因为在两次读取之间,数据被其他事务修改了。
事务 A 在两次读取某一账户余额的过程中,事务 B 对该账户余额进行了修改。假设事务 A 第一次读取账户余额为 1000 元,在事务 A 还没有完成整个事务处理之前,事务 B 将该账户余额修改为 1200 元,然后事务 A 第二次读取时得到 1200 元。这样事务 A 对同一账户余额的两次读取结果不同,出现了不可重复读的情况。
3.幻读
一个事务在按照某个条件进行读取操作后,其他事务插入了满足该条件的新数据,当这个事务再次按照相同条件进行读取时,会发现多了一些原本 “不存在” 的数据,就好像出现了 “幻觉” 一样。幻读主要是因为其他事务插入或删除了符合条件的数据。
事务 A 要查询年龄大于 30 岁的员工名单,第一次查询得到了 3 名员工。此时事务 B 插入了一名年龄大于 30 岁的新员工。当事务 A 再次查询年龄大于 30 岁的员工名单时,发现有 4 名员工,就好像凭空多出来一名员工一样,这种情况就是幻读。幻读和不可重复读的区别在于,不可重复读是针对同一条数据的修改,而幻读是针对符合某个条件的一组数据的插入或删除导致的。
3.2. 事务隔离级别
事务的隔离级别有四个等级:
读未提交(Read Uncommitted): 这是最低的隔离级别。在这个级别下,一个事务可以读取另一个未提交事务的数据。它允许脏读、不可重复读和幻读的发生。
读已提交(Read Committed):在这个隔离级别下,一个事务只能读取另一个已提交事务的数据。可以避免脏读,但不可重复读和幻读仍然可能发生。
可重复读(Repeatable Read):在这个隔离级别下,一个事务在对同一数据进行多次读取操作时,能保证读取的数据是相同的,即可避免不可重复读。但是幻读仍然可能发生。
串行化(Serializable):这是最高的隔离级别。在这个级别下,事务之间是完全串行执行的,就像一个一个排队执行一样,不存在并发执行的情况。可以避免脏读、不可重复读和幻读。
不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性就越差。
mysql默认的事务隔离级别为可重复读,而Oracle和SQL Server是 read committed。
事务操作命令:
start transaction; #开启事务
commit; #提交事务
rollback; #回滚事务:就是事务不执行,回滚到事务执行前的状态
设置事物的隔离级别:
#设置当前mysql连接的隔离级别:
set session transaction isolation level read uncommitted;
#设置数据库系统的全局的隔离级别:
set global transaction isolation level read uncommitted;
注意:
第一种这种会话级别的设置是临时的。当会话结束(比如客户端断开连接)后,这个设置就会失效。下一次重新连接到数据库时,隔离级别会按照数据库的默认设置或者全局设置来确定。它不会对数据库的整体配置产生长期的影响。
第二种全局设置会影响数据库系统的整体配置。这种设置在数据库服务器重新启动之前会一直有效(前提是没有再次修改这个全局设置)。不过,有些数据库系统可能需要额外的配置才能在重启后仍然保持这个全局设置,因为在某些情况下,数据库重启可能会恢复到默认的隔离级别设置。
下面,我会分别演示数据库在不同隔离级别下发生的不同情况,在演示之前我们需要进行如下两步操作。
1. 首先先简单准备一张数据表:
使用显式事务的前提是你得先把自动提交事务的功能给禁用。禁用自动提交功能就是设置autocommit
变量值为0(0:禁用 1:开启)
首先通过命令查看autocommit的值:
2. 将自动提交事务功能禁用:
完成以上两部操作之后,我们就可以开始我们的演示了
第一种情况,读未提交
假设,左边图是我们的事务一,右边是事务二,从图中我们可以看出,事务一开启事务之后,对表进行了查询操作,此时事务二也开启了事务,同时对表进行了修改操作,事务二读到了事务一未提交的事务,这就发生了并发问题中脏读的问题,可见read uncommitted隔离级别的特点:
读未提交隔离级别啥并发问题都没解决,不管你提没提交事务,我都可以读到你的变化
接下来是我要演示的第二种情况,
read committed(读已提交)
演示之前,一定要修改数据库隔离级别和关闭自动提交事务,来确保演示正常进行;
从上图可知,在读已提交的隔离级别下,左边事务一并不能读到右边事务二未提交的事物,当事务二提交事务后,事务一才可以读取到修改后的数据。同时可以说明读已提交解决了脏读的问题。
接下来是我要演示的第三种情况,
repeatable read(可重复读)
该隔离级别为mysql的默认隔离级别;它对某字段进行操作时,其他事务禁止操作该字段。它总能保持你读取的数据是一致的。
在可重复读的隔离级别下能够解决脏读,不可重复读并发两个问题。
先将事务隔离级别改为默认隔离级别即可重复读,随后开启事务一对表中数据进行修改,开启事务二也对表中数据进行修改,在事务一为提交事物的情况下,事务二是阻塞状态。
上图可以看到,在可重复读的隔离级别下,如果事务一的修改数据没有提交的情况下,事务二继续对数据进行操作就会被阻塞。
当时事务一提交事务后,事务二才会运行。
serializable(串行化)
该隔离模式下执行的事务在对某表进行操作期间,禁止其他所有事务对该表进行任何操作。在开发过从中,由于串行化的隔离级性能非常低,所以基本用不到,在这我就不演示了。
事务的保存点(Savepoint)
设置保存点
- 在 MySQL 中,可以使用
SAVEPOINT
命令来设置保存点。语法格式为:SAVEPOINT 保存点名称;
。例如,SAVEPOINT sp1;
就创建了一个名为sp1
的保存点。保存点名称可以根据实际需要自行定义,但需要保证在同一个事务中保存点名称的唯一性。
回滚到保存点
- 当事务执行过程中需要回滚到某个保存点时,可以使用
ROLLBACK TO SAVEPOINT
命令。语法格式为:ROLLBACK TO SAVEPOINT 保存点名称;
。例如,ROLLBACK TO SAVEPOINT sp1;
会将事务回滚到名为sp1
的保存点处,撤销保存点之后的所有操作,但保留保存点之前的操作结果。
释放保存点
- 可以使用
RELEASE SAVEPOINT
命令来释放已经定义的保存点。语法格式为:RELEASE SAVEPOINT 保存点名称;
。例如,RELEASE SAVEPOINT sp1;
会释放名为sp1
的保存点。释放保存点后,该保存点就不能再被回滚到了,但事务仍然可以继续执行其他操作或设置新的保存点。
4. 持久性
持久性是指一旦事务提交,它对数据库中数据的改变就应该是永久性的。即使系统可能出现故障,如断电、系统崩溃等,已提交事务的数据修改也不会丢失。比如,在事务提交后,数据库将数据更新记录到磁盘等持久存储介质中,这样后续即使数据库服务重启,数据的修改依然存在。
以上。
标签:总结,事务,隔离,数据库,提交,MYSQL,级别,读取 From: https://blog.csdn.net/duehebfbf/article/details/143640166