MySQL事务详解

什么是事务

事务就是一组DML语句组成,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部失败,是一个整体。

为什么要有事务

1.事务是数据库维护数据一致性的基本单位,在每个事务结束时,都能保证数据一致性。

2.事务的提出主要是为了解决并发情况下保持数据一致性的问题。

如何使用事务

对于单挑SQL语句,会被MySQL自动包装成事务。

对于多条SQL语句,需要如下操作:

begin //或者 start transaction
SQL1;
(savepoint p1; 中途可以设置回滚点)
SQL2;
...
(rollback p1; 回滚到设置的回滚点,若未设置,则默认回滚到事务最开始的状态)
commit;

事务的属性

原子性

一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

隔离性

隔离性是什么?

隔离性是MySQL的内部机制,让并发执行的各个事务,看到不同的数据修改(增删改),就叫做隔离性。

隔离级别是什么?

我们作为一个事务,可以看到不同可见性的数据,程度的不同,叫做隔离级别。

隔离级别解决的问题

脏读

一个事务执行时,读到了另一个事务未提交的数据。这种现象叫做脏读。

不可重复读

同一个事务内,同样的读取,在不同的时间段,读取到了不同的值。这种现象叫做不可重复读。重点是修改和删除。

幻读

幻读是不可重复读的一种特殊情况,重点在于新增。同样的条件,第一次和第二次读出来的记录数不一样。

这里的幻读仅指插入,不包含更新或删除后,查询到不一样的记录数。

一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据(为什么?因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题),会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读。很明显,MySQL在RR级别的时候,是解决了幻读问题的。

隔离级别分类

读未提交(Read Uncommited)

在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等。

读提交(Read Commited)

该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读和幻读的问题。

可重复读(Repeatable Read)

这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题(MySQL解决了该问题)。

串行化(Serializable)

这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了脏读、不可重复读和幻读等问题。它在每个读的数据行上面加上共享锁,但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)。

如何做到隔离级别?

MySQL通过MVCC机制实现了隔离级别。

为什么要存在隔离级别?

不仅仅是为了考虑安全问题,是在安全和效率之间,找平衡点。至于为什么存在多种隔离级别,是因为隔离级别的选择是由上层决定的,MySQL只是提供多种方案供上层选择。

安全体现在:数据具有隔离性,MySQL在RR级别下帮我们解决了脏读、不可重复读和幻读等问题,所以我们读到的数据是安全的。

效率体现在:在保证隔离级别的情况下,采用多版本并发控制(MVCC),让删,改,增加使用当前读,让读取使用快照读。对于同时进行的多事务而言时,因为隔离性的存在,写当前数据,读历史数据,使得当前读和快照读并发执行。

持久性

事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

一致性

在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

一致性不是一种具体的方案,而是事务维护的最终目标。由用户和MySQL共同决定

RC与RR的本质区别

三个列隐藏字段

  • DB_TRX_ID :6 byte,最近修改( 修改/插入 )事务ID,记录创建这条记录/最后一次修改该记录的事务ID。

  • DB_ROLL_PTR : 7 byte,回滚指针,指向这条记录的上一个版本(简单理解成,指向历史版本就行,这些数据一般在 undo log 中)。

  • DB_ROW_ID : 6 byte,隐含的自增ID(隐藏主键),如果数据表没有主键, InnoDB 会自动以 DB_ROW_ID 产生一个聚簇索引。

  • 补充:实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了。

undo log

MySQL 中的一段内存缓冲区,用来保存日志数据。

Read View

  1. 决定一个事务的可见性的数据结构,记录一个事务能看到那些历史版本的数据。

  2. 一个事务启动,一旦形成Read View,Read View如果不变,该事务可以看到的历史版本也就是确定的。一旦我们发生了快照读,读视图得到了确认,后续的快照读就会依赖首次出现的快照读。即某个事务中首次出现快照读,决定该事务后续快照读结果的能力。

ReadView是MySQL底层中的一个类,其结构的核心字段如下:

 

读的策略源码如下:

RR级别下

当一个事务首次 select(不加锁的快照读)时,会形成快照及Read View。一旦形成Read View,就不会再更新。所以RR级别下,没有不可重复读和幻读的问题。

RC级别下

一个事务在每次读快照时,都会新生成一个快照和Read View。所以RC级别下,会存在不可重复读的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

waywt1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值