并发事务正确性的准则 可串行化_事务的隔离级别

定义

在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。

用途

事务的隔离级别是为了保证并发读取数据的正确性。

我们的应用在并发处理请求时,对数据库的访问也是并发的,这样就会产生多个事务同时对数据库中某条记录进行增删改查的场景,开发者要根据具体场景采取不同的隔离级别,在系统处理效率和数据安全之间寻找一种平衡。

详解

下面以一个例子来展示,数据库采用mysql。

准备工作

l 创建数据库,并插入两条数据:

CREATE TABLE `txiso` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(32) DEFAULT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `txiso` (`id`, `name`)

VALUES

(1,'小明'),

(2,'小刚');

l 开启两个命令行窗口,分别连接到mysql,模拟两个事务

l 取消两个事务的自动提交:set session autocommit=0;

l 将两个会话的数据库的事务隔离级别降到最低:读未提交

set session transaction isolation level read uncommitted;

问题1:脏读

l 定义:

一个事务在读的时候,另外一个事务正在修改。导致第一个事务读取

l 示例:

396ba9148e09866c6fac8dc97c2a0b33.png

在上面的场景中,第3步执行查询时查到第2步未提交的数据。如果第一个事务稍后进行了回滚操作,则导致第二个事务一直会以错的数据进行处理。

l 解决方案:

调高事务隔离级别到:读已提交(set session transaction isolation level read committed;)。此时示例执行如下:

cd9db865edcd8d2c61422ec60cb20eea.png

这里第2步的查询并没有查到第一个事务中未提交的数据,只有等第一个事务在第3步完成提交后第二个事务菜查到新增的数据“小红”。这样脏读的问题就解决了。

但是又会出现其他问题:不可重复读。

问题2:不可重复读

l 定义:

一个事务对同一行数据重复读取两次,但是却得到了不同的结果。这里包含两种情况:

(1) 虚读:事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值(针对修改)

(2) 幻读:事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(针对增删)

很多人把不可重复读和幻读放到同一级别上来讲,个人认为其实是不太合适的。

l 示例:

1744171e2df870ecacb086dc837eba4d.png

在第二个事务执行步骤3之后,第一个事务执行了4、5、6步,插入一条数据“小军”;然后第二个事务又执行了一次查询,结果发现多了一条记录,类似于人产生了幻觉。虚读的情况与之类似,不在赘述。

l 解决方案:继续调高事务的隔离级别到:可重复(set session transaction isolation level repeatable read;)。此时执行结果如下:

0310a496ff9b02c70e8e72741b4157b0.png

只要事务启动起来后,无论外面怎么操作数据,事务内部读到的总是和第一次一样,第2、5、7步读到的数据都是一样的。

其实这样也有问题,就是如果事务二在执行的过程中对数据作了一次update操作,然后再查就会发现多出一条记录来,现象跟幻读一致。这也可能是人们把幻读和不可重复读分开表述的原因(在可重复读的隔离级别下仍然会出现数据不能重复读取的问题,主要在于一直负责读取的那个事务在两次读取之间有没有执行增删改操作),也就出现了总结部分的那张表。那么这种问题如何解决呢?答案就是继续调高事务隔离级别到:串行化(set session transaction isolation level serializable;)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读。此时如果事务一正在修改数据时,事务二来读取数据则必须等待直至超时。这对于应用来说基本上是不可接受的,除非你的系统用户都是顺序使用的,否则就会有用户因为查询被卡住。这个级别基本没人用,就不研究了。

总结:

l mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读,基本行业满足大部分应用的需求了。

l 事务隔离级别和问题之间的关系:

30f2deaf2c4cd7bcacc95e704bb82ac4.png

示例中用到的命令

//关闭自动提交

set session autocommit=0;

//查询事务隔离级别

select @@transaction_isolation;

//设置read uncommitted级别:

set session transaction isolation level read uncommitted;

//设置read committed级别:

set session transaction isolation level read committed;

//设置repeatable read级别:

set session transaction isolation level repeatable read;

//设置serializable级别:

set session transaction isolation level serializable;

参考资料:

l https://baike.baidu.com/item/事务隔离级别/2638091?fr=aladdin

l https://baijiahao.baidu.com/s?id=1629344395894429251&wfr=spider&for=pc

http://www.zsythink.net/archives/1233

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值