面试官:事务隔离级别和锁有什么关系(上)| 8月更文挑战

590 阅读4分钟

前言

前几天面试的时候,面试官问了一个问题:说一下数据库的事务隔离级别,这不是手到擒来的吗,咔咔咔我就一顿爆说,顺便把各个级别对应的问题也一并说了,说的是那个昏天暗地,乌漆麻黑。

然后面试官又问了一个:那你知道有多少种锁吗,我又是一顿爆说,从粒度,到应用到系统级别都给他说了一遍,从面试官的目光里,我看到了光 —— 这是一个我要的人

unnamed.gif

那我再问一个,我现在范围性的改也就是update xxx where id < xxx 这样子,你说它用的是行锁,那么它会锁住几条数据呢。

完了,这波大意了,没复习到这个,虽然不会,但也要非常淡定的说:where几条就几条。

从面试官逐渐暗淡的眼神中,我知道我这波凉了。

拖着疲惫的身体,回到了家,查了一轮资料,我决定总结一波经验,方便下一次遇到同样的问题,也可以一顿爆说。

事务中是怎么做到隔离的

首先一点,我们都知道MySQL用的是InnoDB引擎,而对于InnoDB来说,默认的隔离级别是可重复度(Repeatable Read),而对于其他数据库来说(例如PgSQL等)它们的隔离级别是读已提交(Read Committed),这里我只会对这两种隔离级别做讨论,另外两个很少用到,这里就不做讨论。

对于RR级别的隔离来说,会存在一个幻读的问题,这里来科普一下什么是幻读

就是事务A去仓库里面看了一下编号为1的货物有几个,嗯,有一个,这时候,事务B偷偷的往仓库里面又放了一个编号为1的货物,然后就溜了(提交了事务),这时候事务A为了保险起见,又去查了一次编号为1的货物,咦,怎么变成了两件了,刚刚还一件的,这个就是幻读。

对于RC级别的隔离来说,又会存在一个不可重复读的问题,那么这里再来科普一下什么是不可重复度

事务A又来到了仓库里面,去查了一下编号为1的货物是什么货物,嗯,是PS5,这时候,事务B又来了,这次他找到了1号货物,并把里面的PS5给调包成了PS4,然后又溜了,这时候事务A又一次去查了一波1号货物是啥,然后发现东西被调包了,这个就是不可重复度。

其实本质上来说,幻读和不可重复读的都是在二次读数据的时候,数据不一致的问题,但是两个又存在一个微笑的区别,那就是幻读主要针对的是Insert操作,而不可重复度则是针对于Update和Delete操作

锁在事务中的作用

我们知道,锁的范式一共可以分为两种:一次封锁和两段锁

一次封锁的意思就是在事务开始的时候,就把要处理的数据行给锁起来,然后等事务处理结束之后,在把锁给释放,这样的方式,具有很好的并发性,同时也不会出现死锁的情况。

两段锁则是在事务里面一句句的去枷锁,例如查询的时候,就给数据行加一个读锁(读锁互相兼容),在写数据的时候,则是会给数据行加一个写锁(独占的锁)。

看起来是事务使用一次封锁所带来的效果会更好,但实际上,我们知道数据库的事务是会死锁的,也就是并没有使用一次封锁的方式,因为在事务开始前,数据库并不知道具体要锁住哪些行,所以其实事务使用的其实是两段锁的范式,虽然说这种方式降低了一个并发性,但是可以保证串行化执行,而在并发条件下,串行化执行是非常重要的一个点。

最后

本来是想一篇万字长文的,刚好撞上掘金更文挑战,我觉得分成上下部分来更了

src=http___b-ssl.duitang.com_uploads_item_201503_29_20150329111903_WhVdy.thumb.700_0.jpeg&refer=http___b-ssl.duitang.jpg