破案了,Mysql并没有完全解决幻读问题

前言

一、事务是什么?

事务(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)

破案了,Mysql并没有完全解决幻读问题_第1张图片


测试开始

事务级别为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了。

破案了,Mysql并没有完全解决幻读问题_第2张图片

#读未提交,其实就是可以读到其他事务未提交的数据,但没有办法保证你读到的数据最终一定是提交后的数据,如果中间发生回滚,那就会出现脏数据问题,读未提交没办法解决脏数据问题。

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

RC-读提交;

set global transaction isolation level read committed;

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

begin;
select * from test where id =2

破案了,Mysql并没有完全解决幻读问题_第3张图片

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

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

破案了,Mysql并没有完全解决幻读问题_第4张图片

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

破案了,Mysql并没有完全解决幻读问题_第5张图片
在同一事务中(本例中的事务B),事务的不同时刻同样的查询条件,查询出来的记录内容是不一样的,事务A的提交影响了事务B的查询结果,这就是不可重复读。

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

set global transaction isolation level repeatable read;

事务1第一次查询是空的结果

事务2 第二次查询还是空的结果

破案了,Mysql并没有完全解决幻读问题_第6张图片

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

破案了,Mysql并没有完全解决幻读问题_第7张图片

总结

结论:在rr级别下,MySQL InnoDB并不保证避免幻读,没有完全解决快照读下的幻读问题,mysql使用mvcc利用历史数据只是部分避免了幻读(在某些场景看上去规避了幻读),要完全避免,需要手动加锁将快照读调整为当前读(mysql不会自动加锁)。

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

然后mysql使用next-key完全避免了幻读。

你可能感兴趣的:(mysql数据库sql)