学习《MySQL高级》锁和事务,并参考其余优良相干文章整顿的笔记

表锁

读锁会阻塞写,然而不会梗塞读;写锁会把读锁和写锁都阻塞。

详解:
会话s1给表A加读锁,s1、s2……都不可写表A,可读表A;
会话s1给表A加写锁,s1可对表A增删改查,s2、s3等未拿到锁的会话,既不能查也不能写;
会话s1不论是表A加读锁还是写锁,须要等表A的锁开释后能力操作其余没有加锁的表(能够给多个表加锁,同时操作多个表)。

PS:读锁,又叫共享锁(S锁);写锁,又叫排他锁(X锁)。

行锁

行锁反对事务

事务

什么是事务?事务是数据库操作的最小工作单元,组合一组操作一起提交,要么执行都胜利(commit),要么执行都不胜利(rollback)。

事务的个性(ACID)

  • Atomicity:原子性
  • Consistency:一致性
  • Isolation:隔离性
  • Durability:持久性

原子性

事务被视为不可分割的最小单元,事务的所有操作要么全副胜利,要么全副失败回滚。

一致性

数据库在事务执行前后都放弃一致性状态,在一致性状态下,所有事务对一个数据的读取后果都是雷同的。

隔离性

一个事务所做的批改在最终提交以前,对其余事务是不可见的。

持久性

一旦事务提交,则其所做的批改将会永远保留到数据库中。即便零碎产生解体,事务执行的后果也不能丢。

并发事务处理带来了哪些问题

  • 更新失落 (Lost Update)
  • 脏读 (Dirty Reads)
  • 不可反复读 (Not-Repeatable Reads)
  • 幻读 (Phantom Reads)

更新失落

当两个或多个事务抉择同一行,而后基于最后选定的值更新该行时,因为每个事务都不晓得其余事务的存在,就会产生失落更新问题。最初的更新笼罩了由其余事务所做的更新。

脏读

一句话:事务A读取到了事务B已批改但尚未提交的数据,还在这个数据根底上做了操作。此时,如果B事务回滚,A读取的数据有效,不合乎一致性要求。

不可反复读

一个事务在读取某些数据后的某个工夫,再次读取以前读过的数据,却发现其读出的数据曾经产生了扭转、或某些记录曾经被删除了!这种景象就叫做“不可反复读”。

一句话:事务A读取到了事务B已批改且已提交的数据,不合乎隔离性

幻读

一个事务按雷同的查问条件从新读取以前检索过的数据,却发现其余事务插入了满足其查问条件的新数据,这种景象就称为“幻读”。

一句话:事务A读取到了事务B新增且已提交的数据,不合乎隔离性。

PS: 认真了解加黑的中央,脏读、不可反复读、幻读的区别高深莫测。

事务的隔离级别

读未提交(READ UNCOMMITTED)

事务中的批改,即便没有提交,对其余事务也是可见的。

读已提交(READ COMMITTED)

一个事务只能读取曾经提交的事务所做的批改。换句话说,一个事务所做的批改在提交之前对其余事务是不可见的。

可反复读(REPEATABLE READ)(默认级别)

保障在同一个事务中屡次读取同样数据的后果是一样的。

可串行化(SERIALIZABLE)

强制事务串行执行。

每种隔离级别以及会呈现的问题汇总表

隔离级别脏读不可反复读幻影读
未提交读
提交读×
可反复读××
可串行化×××

查看以后数据库的事务隔离级别:

show variables like 'tx_isolation';

《MySQL实战45讲》03 | 事务隔离:为什么你改了我还看不见?一文解析的更加清晰明了

行锁降级表锁

如果A事务依据条件 a = 1 更新时,索引生效,事务未提交前;B事务依据条件 a = 10 更新时,会被阻塞。由此可见,插入时索引生效导致行锁降级为表锁。

总结:没有索引或者索引生效更新数据时,InnoDB 的行锁降级为表锁。

间隙锁(Gap Lock)

什么是间隙锁?

当咱们用范畴条件而不是相等条件检索数据,并申请共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范畴内但并不存在的记录,叫做“间隙(GAP)”。

InnoDB 也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Gap Lock) 。

Next-Key Lock = Record Lock(行锁)+ Gap Lock(间隙锁),它不仅锁定一个记录上的索引,也锁定索引之间的间隙。

危害

因为Query执行过程中通过范畴查找的话,他会锁定整个范畴内所有的索引键值,即便这个键值并不存在。

间隙锁有一个比拟致命的弱点,就是当锁定一个范畴键值之后,即便某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无奈插入锁定键值范畴内的任何数据。在某些场景下这可能会对性能造成很大的危害。

如何给某一行数据加锁?

# session 1> begin; # 开启手动事务> select * from test where a = 8 for update; # 锁住 a = 8 的这行记录// 此时其余 session 是不能更新此行数据的,直到 session1 会话提交事务,才会将此行的锁开释> commit; # 手动提交事务 

补充:乐观锁和乐观锁

乐观锁和乐观锁并不是仅限于数据库的锁,它们是两种思维,用于解决并发场景下的数据竞争问题。

乐观锁

乐观锁:在操作数据时比拟“乐观”,总认为会有其他人同时批改数据,所以在操作数据时会先把数据加锁,直到操作结束才开释锁,加锁期间其他人不能批改数据。

乐观锁

乐观锁:在操作数据时比拟“乐观”,总认为不会有人同时批改数据,所以在操作数据时不会加锁。更新数据的时候,判断一下在查问后到更新这段时间数据有没有被其他人批改,若他人没有批改数据,则本人失常执行。若他人批改了数据,则本人放弃操作。

乐观锁不加锁并不意味着对数据不负责。它有两种实现形式:CAS机制版本号机制

1.CAS机制(Compare And Swap)

CAS操作包含了3个操作数:

  • 须要读写的内存地位(V)
  • 进行比拟的预期值(A)
  • 拟写入的新值(B)

CAS操作逻辑:如果内存地位V的值等于预期的A值,则将该地位更新为新值B,否则不进行任何操作。
许多CAS的操作是自旋的:如果操作不胜利,会始终重试,直到操作胜利为止。

CAS蕴含了CompareSwap两个操作,它是由CPU反对的原子操作,通过硬件放弃原子性

2.版本号机制

实现思路:在数据记录中减少一个 version (版本号)字段,每次数据被批改时版本号减少1。

当一个会话操作中,先把数据查出,执行操作,对数据进行批改时,
比对版本号是否发生变化,若雷同则证实没有人批改,失常执行批改操作;
若版本号不雷同,则示意这段时间有其余会话操作批改了数据,以后会话须要放弃操作。

乐观锁和乐观锁的优缺点和实用场景?CAS有哪些毛病?

详见【BAT面试题系列】面试官:你理解乐观锁和乐观锁吗?

总结

Innodb 存储引擎实现了行锁,反对事务;MyISAM 存储引擎是表锁。

行锁的性能损耗要比表锁更大,但整体并发解决能力要比表锁更强。

[参考]

MySQL高级_行锁实践
MySQL高级_索引生效行锁变表锁
MySQL高级_间隙锁危害
MySQL高级_如何锁定一行
打工四年总结的数据库知识点
【BAT面试题系列】面试官:你理解乐观锁和乐观锁吗?