事物隔离级别详解(实践)

宏观

在这里插入图片描述

并发造成什么问题?

  1. 脏读 : 一个事物读取了另一个事物未提交的数据
  2. 不可重复读 : 一个事物多次读取一行数据导致前后数据不一致
  3. 幻读: 一个事物读取了别的事物插入的数据

后面会详细的讲解为什么,O(∩_∩)O嘿嘿~

模拟事物隔离级别

事物特性

  1. 原子性A ,指的是不可再次分割, 也就是A和B事物要么成功, 要么失败
  2. 一致性C: 表示,事物读取数据要保证正确,一致性
  3. 隔离性I: 事物A不可以对事物B的数据进行更改
  4. 持久性D: 事物A操作之后数据存储在了磁盘上,不会丢失

隔离级别

  1. 读未提交: 脏读, 不可重复读, 幻读
  2. 读已提交: 不可重复读, 幻读
  3. 可重复读 : 幻读
  4. 串行化 : 安全, 都没有

隔离级别举栗子

首先根据下面的sql结构测试栗子

-- ----------------------------
-- Table structure for t_student
-- ----------------------------
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student` (
  `sno` int(11) NOT NULL,
  `sname` varchar(255) CHARACTER SET gbk DEFAULT NULL,
  `sdree` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
  `ssex` char(255) CHARACTER SET utf8 DEFAULT NULL,
  `sage` decimal(10,0) DEFAULT NULL,
  PRIMARY KEY (`sno`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of t_student
-- ----------------------------
INSERT INTO `t_student` VALUES ('1', 'judy', '天融信', '男', '26');
INSERT INTO `t_student` VALUES ('2', '杜雨', '中银', '男', '26');
INSERT INTO `t_student` VALUES ('3', '雅雯雯', '买卖宝', '男', '27');
INSERT INTO `t_student` VALUES ('4', '子腾', 'IBM', '男', '23');
INSERT INTO `t_student` VALUES ('5', '旭日', '微软', '女', '25');

1 查看当前数据库隔离级别, 设置隔离级别

SELECT @@tx_isolation;
-- 非正常情况下
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

读未提交出现的并发问题

A 窗口执行sql

start transaction;
select * FROM t_student WHERE sno ='1';

结果: 
1	judy	天融信	男	26

B 窗口执行sql

start transaction;
select * FROM t_student WHERE sno ='1';
UPDATE t_student SET sname='wangxuefen' WHERE sno =1;

执行后的结果
1	wangxuefen	天融信	男	26

A 窗口执行查询语句(这句话出现的问题)

select * FROM t_student WHERE sno ='1';

得到结果: 1	wangxuefen	天融信	男	26

B 窗口执行

ROLLBACK;
select * FROM t_student WHERE sno ='1';

得到的结果是
1	judy	天融信	男	26

A 窗口执行

select * FROM t_student WHERE sno ='1';

得到的结果是
1	judy	天融信	男	26

从最后的执行结果中我们可以发现A读取了B未提交的数据, 当B事物回滚的时候, A之前读到的数据变成了脏数据, 这就是脏读

提交读出现的问题

1 更改事物的隔离级别

SELECT @@tx_isolation;
SET SESSION  TRANSACTION ISOLATION LEVEL READ COMMITTED;

A 窗口

start transaction;
select * FROM t_student WHERE sno ='1';

执行结果
1	judy	天融信	男	26

B 窗口

start transaction;
UPDATE t_student SET sname='12' WHERE sno =1;

A 窗口 (出现问题的原因,B还没有提交但是已经读了,发送不可重复读问题)

select * FROM t_student WHERE sno ='1';

执行结果
1	judy		天融信	男	26

B 窗口 (出现问题的原因)

COMMIT

A 窗口

select * FROM t_student WHERE sno ='1';

执行结果
1	12   天融信	男	26

读已提交,出现不可重复读问题

可重复读 REPEATABLE-READ(mysql默认级别)

A 窗口

start transaction;
SELECT * FROM t_student WHERE sno='1'

执行结果:1	judy	天融信	男	26

B 窗口

start transaction;
SELECT * FROM t_student WHERE sno='1';
UPDATE t_student SET sname='wxf' WHERE sno =1;
SELECT * FROM t_student WHERE sno='1';

执行结果
1	wxf	天融信	男	26

A 窗口 (这里可以跟读已提交隔离级别进行对比)

1	judy	天融信	男	26

B 窗口

COMMIT

A 窗口

SELECT * FROM t_student WHERE sno='1'

得到结果:
1	judy	天融信	男	26

从得出的结果可以看出我们已经避免了可重复读的问题, 但是发现最后一次的A窗口得到的结果却不是我们想要的数据,也就是不是最后更改后的数据.

事物隔离级别设置为串行化 Serializable

事物隔离级别是最为安全的,设置隔离级别

SET SESSION tx_isolation='SERIALIZABLE';

A窗口

start transaction ;

B 窗口

start transaction ;

A窗口

SELECT * FROM t_student WHERE sno='1';

得到结果:1	wxf	天融信	男	26

B窗口

  UPDATE t_student SET sname='judy' WHERE sno =1
  
  得到结果: 被卡住了, 无法得到结果

为什么会出现被卡住呢? 原因是因为当A去开启事物并且去执行查询事件, 这个时候B去执行更新操作,那么这个时候会被卡住,原因是因为A的select操作被上了锁, 所以B窗口的update操作是无法执行的, 所以就解决了我们上述所有问题,简单粗暴~

悲观锁

悲观锁分为共享锁和排它锁

什么是共享锁

共享锁的意思是多个事物对一行数据操作的时候, 可以共享一把锁,都可以访问到数据,但是只能读不能更改,写.
排他锁的意思是指当有一行数据是排他锁的时候, 其他事物就不能再获取该锁的其他锁,包括共享锁和排它锁,

A 窗口 ,(FOR UPDATE指的是悲观锁)

START TRANSACTION;

SELECT * FROM t_student WHERE sno ='1' FOR UPDATE

B 窗口

START TRANSACTION;
SELECT * FROM t_student WHERE sno ='1' FOR UPDATE

执行结果:
 被卡住了

乐观锁

依靠数据本身来保证数据的正确性
乐观锁的两种方式
1 使用版本号
2 使用时间戳

A 窗口

SELECT * FROM t_student WHERE sno='1'
UPDATE t_student SET sname='judy',version=version+1 WHERE sno='1'

B窗口

SELECT * FROM t_student WHERE sno='1'
UPDATE t_student SET sname='judy',version=version+1 WHERE sno='1' AND version =1

如果你再说看不懂, 哼 我就生气了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章