欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

事务的隔离级别- 极客时间()

程序员文章站 2022-08-29 09:34:23
初识事务隔离 事务隔离级别的出现都是针对数据库的具体问题的, SQL 92标准对事务并发处理会存在的异常情况进行了分级, 分别为脏读(Dirty Read)、不可重复读(Unrepeatable Read)和幻读(Phantom Read). 三种异常 举个例子, 有个heros_temp表, 中有 ......

初识事务隔离

事务隔离级别的出现都是针对数据库的具体问题的, sql-92标准对事务并发处理会存在的异常情况进行了分级, 分别为脏读(dirty read)、不可重复读(unrepeatable read)和幻读(phantom read).

三种异常

举个例子, 有个heros_temp表, 中有三条数据:
事务的隔离级别- 极客时间()

先说脏读, 现在访问数据库, 对数据库进行了一次insert操作, 插入一条"吕布"的记录, 事务未提交, 现在重新开启一个事务, 查询数据库可以将吕布的记录查询出来. 这个就是脏读.

不可重复读呢? 现在先查询数据库记录, 之后重新开启一个事务, 修改一条记录, 现在在前一个事务中再次查询可以查询出修改后的数据, 前后查询出的数据不一致. 这个就是不可重复度.

幻读呢? 现在先查询数据库, 之后开启新事务insert一条记录, 在第一个事务中再次查询会多出插入的记录, 这个就是"幻读".

  1. 脏读: 读到事务中还没有提交的数据(可能事务回滚, 这个时候读到的数据无意义)
  2. 不可重复读: 对某数据进行读取, 发现两次读取的结果不同, 也就是没有读到相同的内容.(重点在于一条数据的修改, 也就是update 和 delete) 这个因为有其他事务对这个数据同时进行了修改和删除.
  3. 幻读: 事务a根据条件查询得到了n条数据, 但此时事务b更改或者增加了m条符合事务a查询条件的数据, 这样当事务a再次进行查询的时候大仙有n + m条数据, 产生了幻读.(重点在于新增多条记录insert)

事务的隔离级别有哪些?

解决异常数量从少到多的顺序决定了隔离级别的高低, 这四种隔离级别从低祷告分别是: 读未提交(read uncommitted)、读已提交(read committed)、可重复读(repeatable read)和可串行化(serializable). 这个隔离级别解决的异常情况如下:
事务的隔离级别- 极客时间()

读未提交,也就是允许读到未提交的数据,这种情况下查询是不会使用锁的,可能会产生脏读、不可重复读、幻读等情况。

读已提交就是只能读到已经提交的内容,可以避免脏读的产生,属于 rdbms 中常见的默认隔离级别(比如说 oracle 和 sql server),但如果想要避免不可重复读或者幻读,就需要我们在 sql 查询的时候编写带加锁的 sql 语句。

可重复读,保证一个事务在相同查询条件下两次查询得到的数据结果是一致的,可以避免不可重复读和脏读,但无法避免幻读。mysql 默认的隔离级别就是可重复读。

可串行化,将事务进行串行化,也就是在一个队列中按照顺序执行,可串行化是*别的隔离等级,可以解决事务读取中所有可能出现的异常情况,但是它牺牲了系统的并发性。

模拟异常

模拟的数据库表如下:

-- ----------------------------
-- table structure for heros_temp
-- ----------------------------
drop table if exists `heros_temp`;
create table `heros_temp`  (
  `id` int(11) not null,
  `name` varchar(255) character set utf8 collate utf8_general_ci not null,
  primary key (`id`) using btree
) engine = innodb character set = utf8 collate = utf8_general_ci row_format = dynamic;

-- ----------------------------
-- records of heros_temp
-- ----------------------------
insert into `heros_temp` values (1, '张飞');
insert into `heros_temp` values (2, '关羽');
insert into `heros_temp` values (3, '刘备');

开启两个客户端, 由于mysql的默认隔离级别是可重复度, 所以需要先将级别设为读未提交:

mysql> show variables like 'transaction_isolation'; // 查询当前隔离级别
mysql> set session transaction isolation level read uncommitted; // 设置隔离级别为读未提交
mysql> set autocommit = 0; // 设置事务不自动提交(由于mysql的事务是自动提交的, 这里需要改一下)
脏读

客户端2中开启事务, 写入新英雄, 不要提交
事务的隔离级别- 极客时间()

客户端1中查看
事务的隔离级别- 极客时间()

模拟不可重复读

客户端1查询
事务的隔离级别- 极客时间()

客户端2修改
事务的隔离级别- 极客时间()

客户端1再次查询
事务的隔离级别- 极客时间()

模拟幻读

客户端1查询
事务的隔离级别- 极客时间()

客户端2新增
事务的隔离级别- 极客时间()

客户端1再次查询
事务的隔离级别- 极客时间()

隔离级别都是针对对应的异常问题, 并且隔离级别针对每种rdbms都是相同的, 不同的是实现的原理不同.
事务的隔离级别- 极客时间()