关于mysql:破案了Mysql并没有完全解决幻读问题

4次阅读

共计 2247 个字符,预计需要花费 6 分钟才能阅读完成。

前言

一、事务是什么?

事务(Transaction),个别是指要做的或所做的事件。在计算机术语中是指拜访并可能更新数据库中各种数据项的一个程序执行单元 (unit)。事务通常由高级数据库操纵语言或编程语言(如 SQL,C++ 或 Java)书写的用户程序的执行所引起,并用形如 begin transaction 和 end transaction 语句(或函数调用)来界定。事务由事务开始(begin transaction) 和事务完结 (end transaction) 之间执行的整体操作组成。

二、事务四大个性

1. 原子性

事务是数据库的逻辑工作单位,事务中蕴含的各操作要么都做,要么都不做

2. 一致性

事 务执行的后果必须是使数据库从一个一致性状态变到另一个一致性状态。因而当数据库只蕴含胜利事务提交的后果时,就说数据库处于一致性状态。如果数据库系统 运行中产生故障,有些事务尚未实现就被迫中断,这些未实现事务对数据库所做的批改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不统一的状态。

3. 隔离性

一个事务的执行不能其它事务烦扰。即一个事务外部的操作及应用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能相互烦扰。

4. 持久性

也称永久性,指一个事务一旦提交,它对数据库中的数据的扭转就应该是永久性的。接下来的其它操作或故障不应该对其执行后果有任何影响。

三、环境筹备

MySQL:5.7
winows 10
Navicate for Mysql 11.1

脚本和数据库筹备

筹备一张 test 表和简略插入几条数据, 主键 id 列和年龄 age 列

DROP TABLE IF EXISTS `test`;。CREATE TABLE `test` (`id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES ('1', '2');
INSERT INTO `test` VALUES ('2', '10');
INSERT INTO `test` VALUES ('3', '4');
INSERT INTO `test` VALUES ('4', '5');
INSERT INTO `test` VALUES ('5', '6');

查问主动提交状态

show VARIABLES like 'autocommit'

勾销主动提交

set autocommit = off;

查问全局事务

select @@global.tx_isolation;

四、事务的几种隔离级别和验证

1. 读未提交(READ UNCOMITTED)

2. 读提交(READ COMMITTED)

3. 可反复读(REPEATABLE READ)

4. 串行化(SERIALIZABLE)


测试开始

事务级别为 RU- 读未提交;(产生脏读景象)

set global transaction isolation level read uncommitted;

# 设置实现后,只对之后新起的 session 才起作用,对曾经启动 session 有效。如果用 shell 客户端那就要从新连贯 MySQL,如果用 Navicat 那就要创立新的查问窗口。

创立新的查问接口

事务 1 执行 update 语句

BEGIN;
update  test set age ='7' where id ='2';
COMMIT

事务 B 执行 select 语句

begin;
select * from test where id =2

事务 1 并未提交,事务 2 进行查问的时候,age 的值曾经是 7 了。

# 读未提交,其实就是能够读到其余事务未提交的数据,但没有方法保障你读到的数据最终肯定是提交后的数据,如果两头产生回滚,那就会呈现脏数据问题,读未提交没方法解决脏数据问题。

事务级别为 RC- 读提交;(产生不可反复度景象)

RC- 读提交;

set global transaction isolation level read committed;

事务 1 执行查问 age 值的操作,此时 age 的值为 6

begin;
select * from test where id =2

事务 2 执行 update 操作,更新 age 的值为 6

BEGIN;
update  test set age ='10' where id ='2';
COMMIT

事务 1 再次查问执行 select,发现此时 age 的值扭转了,变成了 10.


在同一事务中(本例中的事务 B),事务的不同时刻同样的查问条件,查问进去的记录内容是不一样的,事务 A 的提交影响了事务 B 的查问后果,这就是不可反复读。

事务级别为 RR- 可反复读;(产生幻读景象)

set global transaction isolation level repeatable read;

事务 1 第一次查问是空的后果

事务 2 第二次查问还是空的后果

事务 1 中执行插入同样数据的操作,发现报错。

总结

论断:在 rr 级别下,MySQL InnoDB 并不保障防止幻读,没有齐全解决快照读下的幻读问题,mysql 应用 mvcc 利用历史数据只是局部防止了幻读(在某些场景看上去躲避了幻读),要完全避免,须要手动加锁将快照读调整为以后读(mysql 不会主动加锁)。

Select  * from test where id =‘8’for update;

而后 mysql 应用 next-key 完全避免了幻读。

正文完
 0