MySQL事务

系列文章目录

一、MySQL数据结构选择
二、MySQL性能优化explain关键字详解
三、MySQL索引优化
四、MySQL事务
五、MySQL锁机制
六、MySQL多版本并发(MVCC)机制


一、MySQL事务特性

1.1、什么是事务

  简单来说,事务是指对于一组操作的集合,这些操作要么全部执行,要么全部不执行,确保数据的一致性和完整性。事务的核心目标是保证在多个操作过程中,即使发生故障,数据也能保持一致的状态。
  事务并非是数据库特有的概念,操作系统中也有事务的概念,比如文件系统中的原子操作,要么执行完毕,要么不执行。以及在在分布式系统中,事务用于保证跨多个系统或服务的操作的一致性。

1.2、事务的特性

  在数据库中,事务是为了保证数据在多用户环境下的可靠性、完整性和一致性。数据库事务通常有以下四个特性,简称 ACID 特性:

  • 原子性(Atomicity):事务是一个“原子”操作,要么全都成功,要么全都失败,不会有中间状态。即使系统发生崩溃或其他错误,事务中的所有操作也不会被部分提交。
  • 一致性(Consistency):事务执行前后,数据库的状态是一致的。事务的执行必须保持数据库的一致性约束(例如数据的完整性和规则)。
  • 隔离性(Isolation):事务的执行应该是隔离的,即使多个事务并发执行,每个事务执行时都不应受到其他事务影响,其他事务的数据变动对当前事务是不可见的,直到当前事务完成。
  • 持久性(Durability):事务一旦提交,其修改的数据将永久保存在数据库中,即使系统发生崩溃或停机,事务的结果也不会丢失。

1.3、MySQL如何保证事务特性

  对于原子性,MySQL通过undolog实现,undolog中记录的是操作的历史,比如在A事务中,首先执行了一条insert语句,对应地在undolog中,就会记录对应的delete语句(反向sql),将来事务需要回滚时,就执行undolog中的该条sql。
  对于一致性,MySQL每次事务执行前后会检查数据库约束(如唯一性约束、外键约束等)是否成立。如果执行的操作违反了数据库的约束,MySQL 会回滚该事务。
  对于隔离性,MySQL通过MVCC机制,,以及隔离级别进行控制。
  对于持久性,MySQL通过Redo Log 来保证数据的持久性。每当事务提交时,InnoDB 会将事务的修改记录到Redo Log文件中。即使发生系统崩溃,在恢复过程中,InnoDB 可以通过重做日志恢复事务提交的操作。
图片来源:图灵学院图片来源:图灵学院

二、MySQL隔离级别

  MySQL隔离级别有以下四种,按从低到高的顺序,隔离级别越高,粒度越细,相应的并发度越低。

  • Read Uncommitted(读未提交):一个事务可以读取其他事务未提交的数据,可能会导致“脏读”。
  • Read Committed(读已提交-不可重复读):一个事务只能读取其他事务已提交的数据,避免了“脏读”。
  • Repeatable Read(可重复读):在事务开始时,读取的数据在整个事务期间都不会变化,防止了“不可重复读”。
  • Serializable(串行化):最严格的隔离级别,事务之间完全串行执行,避免了所有并发问题,但会导致性能下降。

  下面用一个案例演示一下四种隔离级别:

CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('lilei', '450');
INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('hanmei', '16000');
INSERT INTO `test`.`account` (`name`, `balance`) VALUES ('lucy', '2400');

  表的初始状态:
在这里插入图片描述

2.1、读未提交

  将事务A和B的隔离级别设置为read‐uncommitted,注意,在MySQL 5.7版本以上,用SET transaction_isolation = 'READ-UNCOMMITTED';
在这里插入图片描述
  A和B都开启一个事务,在A中对表中的数据进行查询,不提交事务:
在这里插入图片描述
  在B中对id为1的数据进行修改,也不提交事务:
在这里插入图片描述
  回到A中再次执行查询语句,会发现读取到了B事务没有提交的数据
在这里插入图片描述  如果此时B进行了回滚:
在这里插入图片描述  A对于balance - 50 :
在这里插入图片描述  然后进行查询,发现最终的结果是400,而不是上一步A查询到的4500-50 = 4450。
在这里插入图片描述  而在应用程序中,A是不知道B有没有回滚的。

2.2、读已提交-不可重复读

  将A和B的隔离级别设置为'READ-COMMITTED':
在这里插入图片描述  同样地A和B各自开启事务,然后A先查询余额:
在这里插入图片描述  B对余额增加50,不提交事务:
在这里插入图片描述  A查询余额,读取不到B事务未提交的数据
在这里插入图片描述  B提交事务:
在这里插入图片描述
  A再次进行查询:
在这里插入图片描述
  发现两次读取到的数据不一致。即产生了不可重复读的问题,但是同时也解决了脏读的问题。

2.3、可重复读

  将事务A和事务B的级别设置为'REPEATABLE-READ':
在这里插入图片描述  A和B开启事务,A进行查询,不提交事务:
在这里插入图片描述
  B执行更新语句,并且提交事务:
在这里插入图片描述
  回到A去查询,在读已提交-不可重复读的隔离级别下,当B提交了事务后,A读取到的应该是B提交的最新的结果,但是在可重复读的隔离级别下,A事务没提交之前,读取到的依旧是A第一次查询时的结果,而不是其他事务更新并提交后的结果:
在这里插入图片描述
  如果此时再开另一个C事务,执行完更新语句然后提交:
在这里插入图片描述  A读取到的依旧是最初的值:
在这里插入图片描述  这里使用到了MVCC机制,select操作是快照读(历史版本);insert、update和delete 是当前读(当前版本)。
  如果此时B事务再次开启,并且插入一条新的记录,提交事务:
在这里插入图片描述  在其他的事务中是能查到新增的记录的,同时看到了id为1的balance已经加到了600
在这里插入图片描述  但是在A中依旧查询不到,解决了读未提交的问题。
在这里插入图片描述  在这个时候,在A中对于id为1的数据进行修改操作,这时候再去查询,该条数据就会查询到其他事务的提交结果 + A事务修改的结果:
在这里插入图片描述

小结:上面三种隔离级别的区别:
在读未提交中,A事务可以查询到其他事务未提交的修改。(脏读,幻读)
在读已提交中,A事务只能查询到其他事务已经提交的修改。(不可重复读)
在可重复读中,无论其他事务提交了多少次修改,A事务只会查询到第一次读取的数据(解决了脏读,幻读,不可重复读)。在A事务对该数据进行修改后,方可读取到其他事务的提交结果 + A事务修改的结果。(select操作是快照读(历史版本);insert、update和delete 是当前读(当前版本))

2.4、串行化

  将事务A和事务B的级别设置为'SERIALIZABLE':
在这里插入图片描述  A和B开启事务,A进行查询操作,不提交事务:
在这里插入图片描述  此时B进行更新操作,却发现处于阻塞状态:(如果B进行读取操作,则不会阻塞,涉及到读写锁互斥的概念)
在这里插入图片描述  只有A提交了事务后,B才会解除阻塞。

总结

  总结一下几个概念,以及四种隔离级别的关系,解决的问题:

  • 脏读是指一个事务读取了另一个事务尚未提交的数据。如果另一个事务回滚了,这个“脏”数据就不再有效,但第一个事务已经读取了它,导致数据的不一致。
  • 幻读是指在一个事务中,两次查询结果不一致,即另一个事务在第一个查询后插入、删除或修改了符合查询条件的数据,导致第二次查询结果与第一次不相同。
隔离级别允许的现象描述
读未提交(Read Uncommitted)脏读、不可重复读、幻读事务可以读取其他事务未提交的数据,这导致可能会出现脏读。最低的隔离级别,性能较好,但可能会产生数据不一致的情况。
读已提交(Read Committed)不允许脏读,允许不可重复读、幻读事务只能读取其他事务已经提交的数据,避免了脏读,但仍然允许不可重复读和幻读。
可重复读(Repeatable Read)不允许脏读、不允许不可重复读,允许幻读事务在整个过程中读取到的数据不会改变,避免了脏读和不可重复读,但仍然可能会发生幻读。
串行化(Serializable)不允许脏读、不可重复读、幻读最严格的隔离级别,事务按照串行顺序执行,避免了所有的并发问题,但性能最差。
MySQL 事务是指一组数据库操作,这些操作要么全部执行,要么全部不执行,其目的是保证在并发环境下,数据的一致性和完整性。MySQL 事务具有 ACID 性质,即原子性、一致性、隔离性和持久性。 MySQL 中使用事务需要使用 BEGIN、COMMIT 和 ROLLBACK 语句,其中 BEGIN 表示开启一个事务,COMMIT 表示提交事务,ROLLBACK 表示回滚事务事务的基本语法如下: ``` BEGIN; -- 执行一组数据库操作 COMMIT; -- 提交事务 -- 或者 ROLLBACK; -- 回滚事务 ``` 在 MySQL 中,事务的隔离级别分为四个等级,分别是 Read Uncommitted、Read Committed、Repeatable Read 和 Serializable。隔离级别越高,数据的一致性和完整性越高,但同时也会影响数据库的性能。 MySQL 事务的 ACID 性质有以下含义: 1. 原子性(Atomicity):事务中的所有操作要么全部执行成功,要么全部失败回滚,不会只执行其中的一部分操作。 2. 一致性(Consistency):事务执行前后,数据库中的数据必须保持一致性状态,即满足数据库的约束条件和完整性规则。 3. 隔离性(Isolation):事务之间应该是相互隔离的,一个事务的执行不应该被其他事务干扰,保证事务之间的数据相互独立。 4. 持久性(Durability):事务提交后,对数据库的修改应该是永久性的,即使出现系统故障或电源故障,也不应该对数据产生影响。 总之,MySQL 事务是一组数据库操作,具有 ACID 性质,可以通过 BEGIN、COMMIT 和 ROLLBACK 语句来实现,隔离级别越高,数据的一致性和完整性越高,但同时也会影响数据库的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值