mysql事务 MVCC

事务的特性(ACID)

事务要求 ACID 的特性,即:原子性、一致性、隔离性、持久性 。

  1. 原子性:是指整个数据库的每个事务都是不可分割的单位。只有事务中的所有 SQL 语句都执行成功,才算整个事务成功,事务才会被提交。如果事务中任何一个 SQL 语句执行失败,整个事务都应该被回滚。 undolog 来保证

  2. 一致性:是指将数据库从一种一致性状态转换为下一种一致性状态。不允许数据库中的数据出现新老数据都有的情况,要么都是老数据,要么都是新数据。用更书面化的表达就是:数据的完整性约束没有被破坏。

  3. 隔离性:是指一个事务的影响在该事务提交前对其他事务都不可见,它通过锁机制来实现。 mvcc 和 锁 来保证

  4. 持久性:是指事务一旦被提交,其结果就是永久性的。即使发生宕机等故障,数据库也能将数据恢复。 redolog 来保证

事务隔离级别

首先介绍几个概念:

1、 脏读 :事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、 不可重复读 :事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提 交,导致事务A多次读取同一数据时,结果 不一致。

3、 幻读 :系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在 这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生 了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆, 不可重复读 侧重于修改, 幻读 侧重于新增或删除。

读未提交 (read uncommitted)

在该级别,所有的事务都可以看到其他未提交事务的执行结果,本隔离级别很少用于实际应用,因为它的 性能不比其他级别好多少。读取未提交的数据,也称之为脏读。

set global transaction isolation level read uncommitted;
#查看当前隔离级别
select @@global.tx_isolation,@@tx_isolation;

读已提交 (read committed)

事务A只能读取到事务B提交的数据,这种级别可以避免“脏数据” ,这种隔离级别会导致“不可重复读取” ,Oracle默认隔离级别

set global transaction isolation level read committed;
查看当前隔离级别
select @@global.tx_isolation,@@tx_isolation;

可重复读(repeatable read)

是 MySQL 的默认事务隔离级别,它能确保同⼀事务多次查询的 结果⼀致。但也会有新的问题,⽐如级别的事务正在执⾏时,另⼀个事务成功的插⼊了某条数 据,但因为它每次查询的结果都是⼀样的,所以会导致查询不到这条数据,⾃⼰重复插⼊时⼜失败 因为唯⼀约束的原因)。明明在事务中查询不到这条信息,但⾃⼰就是插⼊不进去,这就叫幻读

set global transaction isolation level repeatable read;
查看当前隔离级别
select @@global.tx_isolation,@@tx_isolation;

串行化(SERIALIZABLE)

事务最高隔离级别,它会强制事务排序,使之不会发⽣冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使⽤的场景并不多。

set global transaction isolation level serializable;

查看当前隔离级别
select @@global.tx_isolation,@@tx_isolation;

隔离级别的一致性的关系

隔离级别脏读不可重复读幻读
读未提交可能可能可能
读已提交不可能可能可能
可重复读不可能不可能对innodb不可能
串行化不可能不可能不可能

MVCC

Multi Version Concurrency Control翻译为中文即 多版本并发控制。 用来实现不加锁情况下的读一致性和隔离性。 MVCC使得InnoDB的事务隔离级别下执行一致性读操作有了保证,换言之,就是为了查询一些正在被另一个事务更新的行, 并且可以看到它们被更新之前的值。这是一个可以用来增强并发性的强大的技术,因为这样一来的话查询就不用等待另一个事务释放锁。这项技术在数据库领域并不是普遍使用的。一些其它的数据库产品, 以及mysql其它的存储引擎并不支持它。

mvcc的实现,基于undolog版本链readview

  1. 在 MySQL 命令行的默认设置下,事务是自动提交的,即执行了SQL 语句之后会马上执行 commit 操作,我们可以设置 set autocommit=0 来禁用当前回话的自动提交。

  2. 还可以用 begin 、start transaction 来显式的开始一个事务。

  3. commit 在默认设置下是等价于 commit work 的,表示提交事务。

  4. rollback 在默认设置下等价于 rollback work,表示事务回滚。

  5. savepoint xxx 表示定义一个保存点,在一个事务中可以有多个保存点。

  6. release savepoint xxx 表示删除一个保存点,当没有该保存点的时候执行该语句,会抛出一个异常。

  7. rollback to [savepoint] xxx 表示回滚到某个保存点。

--查询事务自动提交状态 
show variables like '%commit%';

版本链

每行数据都有隐式字段

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

DB_ROLL_PTR 7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)

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

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

读视图(read view)

事务id是递增的只会越来越大,在开启事务的时候,第一次快照读会产生一个读视图,将目前活跃的还未提交的事 务记录下来,并排序出最低事务和最高事务。

我们可以将Read View看作一个数组,整个数组的左边界和右边界时当前活跃事务的事务Id。举个例子 :

现在存活事务有事务100,150,200,250

那么Read View就是{100,150,200,250}

//查询事务Id的语句
SELECT tx.trx_id
FROM information_schema.innodb_trx tx
WHERE tx.trx_mysql_thread_id = connection_id()

Read View几个属性

trx_ids :当前系统活跃(未提交)事务版本号集合。

low_limit_id : 创建当前read view 时“当前系统最大事务版本号+1”。

up_limit_id : 创建当前read view 时“系统正处于活跃事务最小版本号”

creator_trx_id : 创建当前read view的事务版本号;

在每次查询数据的时候,会判断当前行数据最新的事务id trx_id是多少。

  1. trx_id < up_limit_id || trx_id == creator_trx_id(显示) 说明该行的记录早就提交了事务,当前的事务是可见的。 或者该行的最后修改就是本事务提交的,也可见。
  2. trx_id >= low_limit_id(不显示) 读视图(read view) 如果数据事务ID(trx_id)大于read view 中的当前系统的最大事务ID,则说明该数据是在当前read view 创建之后才产生的,所以数据不显示。
  3. 判断 trx_id 是否在活跃事务( trx_ids )中
    1. 不存在 :则说明read view产生的时候事务 已经commit 了,这种情况数据则可以 显示
    2. 已存在 :则代表我Read View生成时刻,你这个事务还在活跃,还没有Commit,你修改的数据, 我当前事务也是看不见 的。

mvcc如何实现RC和RR的隔离级别

(1)RC的隔离级别下,每个快照读都会生成并获取最新的readview

(2)RR的隔离级别下,只有在同一个事务的第一个快照读才会创建readview,之后的每次快照读 都使用的同一个readview,所以每次的查询结果都是一样的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

荷逸同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值