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

初识事务隔离

事务隔离级别的出现都是针对数据库的具体问题的, 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都是相同的, 不同的是实现的原理不同.

posted @ 2019-07-18 10:53  庄子游世  阅读(571)  评论(0编辑  收藏  举报