数据库隔离级别笔记

以下仅为自己整理后的理解,如有不当之处还请指正。

出现背景

在程序中有多线程并发,事务亦如此。为解决事务并发时不同事务间的数据混乱,以及应对不同的场景需要,出现了事务隔离级别。不同的隔离级别对应不同的事务并发下的安全情况,同时也有着不同的性能和问题,需要我们在实际使用时,在利与弊间权衡适合的方式。

事务特性:ACID

-特性英文原文实现方式简介
A原子性Atomicityundolog事务的最小单元,不可再分
C一致性Consistencybinlog、redolog当前事务中的多条语句同时成功或失败
I隔离性Isolation读写锁+MVCC两事务之间具有隔离,在一定程度上互不干扰
D持久性DurabilityACI的共同努力数据必须最终持久化到硬盘等媒介,事务才算成功完成

其中原子性、一致性、持久性是数据库存储的最基本要素,我们在实际应用中,主要是对隔离性进行选择,在性能与可靠性之间权衡。

概述

隔离级别英文简写简述
读未提交Read uncommittedRU能看到其它事务的变更
读已提交Read committedRC其它事务提交后,自己才能看到
可重读Repeatable readRR在整个事务生命周期内,即使数据被别的事务修改并提交了,看到的数据都是启动时的样子
串行1SerializableS同一时刻只允许一个事务执行。读会加读锁,写会加写锁,当读写锁冲突时必须等待先创建的事务执行完成。

在数据操作过程中利用数据库的锁机制或MVCC,获取更高的隔离级别。但随着隔离级别的提升,并发能力随之下降,所以在选择隔离级别时需要权衡取舍。

疑问:

  1. 串行化时,读写锁、写写锁冲突都是单一并发,读读锁冲突呢?是否可以并发?
    一个耗时较长的事务,在最后才可能执行写入,那么在这中间的读操作会锁住吗?
  2. 可重读解决了前后不一致问题,可实际中应该只需要关注最新数据吧,哪些时候会要求前后数据要一致,哪怕读到的是过期数据?

下面是隔离级别及对应的问题一览表:
图例:Y表示有此问题,N表示无此问题

隔离级别脏读不可重复读幻读
读未提交YYY
读已提交NYY
可重读NNY
串行化NNN

可以看到每提升一个级别,问题就少了一些,但对应的性能与并发也受影响下降了一些,在开发中需要权衡使用。

读未提交 RU

其它事务的修改还未提交,就可读取到其结果。相当于隔离级别的裸奔
优点是不需要处理事物隔离,效率高,并发也高。
缺点是有 脏读 等问题。

读已提交 RC

其它事物的修改,必须是已提交成功状态,才能在当前事务中读取到。因此也是对读未提交下脏读问题的解决。
这也是多数数据库软件的默认隔离级别,比如Oracle。
但该级别下会出现当前事务前后两次读取中间,另一事务修改并提交,导致当前事务两次读取结果不一致的问题,称之为 不可重复读 ,解决方法是升级到可重读。

可重读 RR

当前事务前后两次或多次读取之间,即使其它事务修改并提交了,当前事务读取到前后结果仍然是一致的(最早一次的结果)。
需要注意的是,该结果仅是某条已存在数据的修改,如果是另一事务插入了数据,当前事务的count等聚合函数查询仍会出现前后结果不一致问题。

MySQL默认隔离级别即为可重读。而实现这种效果的,主要是MVCC的快照读。

虽然它使得前后读取的数据一样,但当另一事务插入数据并提交后,count等聚合类查询仍会前后不一致,称之为 幻读
解决方法是升级到串行化,以加上排它锁使其它事务不能操作对应数据,但也会造成性能的严重下降。

串行化

顾名思义,事务开启后会上读写锁,该时间段内只有自己能读写锁定范围内的数据。

脏读、不可重复读、幻读

说完了隔离级别,看到里面讲到了三个问题,这里再单独拿出来说明一下

脏读

当前事务读到了另一个事务中的修改结果,但另一个事务还未提交。在读未提交级别下会出现该问题。

不可重复读

假设当前id=1的数据值为100,两个线程都开启事务

操作序号事务A事务B
1获取数据:100
2修改为60
3获取数据:100
4提交事务
5获取结果60

事务B在整个事务期间,受事务A影响,步骤5、7两次获取数据,结果却不一样。

这里有个疑问(在概述章节开头表格下,也有提到)
理论来说,我们应该关注最新值是什么,而对于历史数据并不关心。所以即使前后两次结果不一样,取最后的最新值即可,为什么还要用第一次取到的那个过期值呢???

欢迎留言讨论

幻读

幻读针对的是新数据的插入, 脏读、不可重复读,都是针对现有数据的修改。
幻读是指事务A先count一下数量为100,事务B插入了20条数据,此时事务A再次查询得到120。
但对于期间一些值改变,不再符合统计条件,并不会导致前后count结果不一致。

引用参考


扩展

在整理时涉及的一些相关知识点,做一个简要记录,方便阅览与回忆

MVCC

多版本并发控制(Multi-Version Concurrency Control),由数据库软件实现事务内存,用来解决多事务并发时读写冲突,线程不用争抢读写锁,避免因加锁导致的性能下降。

此外,还需要了解两个概念:当前读、快照读

当前读

是一种悲观锁的操作,他会对当前的读取操作加锁,以保证读取到的数据都是最新的
主要有以下集中加锁操作

  • select lock in share mode(共享锁)
  • select for update(排他锁)
  • update(排他锁)
  • insert(排他锁)
  • delete(排他锁)

快照读

MVCC所提到的读是快照读,也就是普通的select语句不加锁。
mysql单表设计中,除了我们设计的字段,还会自动加两个隐藏字段 trx_idroll_pointer

  • trx_id:事物id。没进行一次事物操作,就会自增1。
  • roll_pointer:回滚指针,用于找到上一个版本的数据,结合undolog回滚。

  1. 串行化的读音:xíng ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值