直接上干货!(都是比较基础的部分,建议对比Redis进行学习,此部分不列举Redis相关内容,请自行查阅资料)
一、锁
作为关系型数据库,MySQL是并发操作的高发地,锁的作用是防止并发操作中出现冲突。MySQL主要操作就是读和写,读操作可以并发,写操作要避免并发。(Redis串行化,不需要!)
1.1 乐观“锁”和悲观锁
乐观锁:认为当前操作的对象上大概率不会存在并发,不需要加锁,仅仅是一种读写策略:
读取操作对象,记录该对象的当前版本号
对读取到的对象进行处理,得到新的对象
校验版本号,如果未变则向数据库写入新对象,已变则不可写回
悲观锁:特点是悲观,是一种真正意义上的锁,可以分为以下类型:
共享锁(S锁,读锁)
排他锁(X锁,写锁)
存在死锁隐患:A和B都需要先读再写对象t,双方都向t增加S锁,然后想将S锁修改为X锁,但是双方S锁的存在意味着无法获取X锁,相互等待造成死锁。
解决:引入更新锁(U锁),加U锁表明既设置S锁,又预定X锁。
在MySQL中,基于悲观锁实现了事务,直接使用事务即可。
悲观锁的作用范围:
行锁
页锁:锁定相邻的几行记录
表锁
1.2 死锁
既然谈到了锁,就不得不提一个很重要的概念:死锁,锁的很多设计都是为了避免死锁。如果学过《操作系统》这门课应该对死锁不陌生,下面列举一些比较重要的概念供读者回顾:
产生死锁的四个必要条件
互斥
不可剥夺
请求和保持
循环等待
二、事务
事务是一组操作的集合,具有ACID特性:
原子性:要么全部完成要么全部不完成(Redis√)
一致性:事务的执行不会破坏事务的完整性约束(Redis√)
隔离性:多个事务并行时,互不影响(Redis√)
持久性:事务一旦提交,操作不丢失(Redis只有AOF的always级别支持)
其中,除了隔离性,其他都好实现,但是如果没有隔离性,又会导致许多问题:
脏读:一个事务读了另一个事务尚未提交的数据
不可重复读:一个事务多次读,但是读到了不同的结果
幻读:事务不独立执行发生的现象,就好像吃了云南见手青
由于事务的隔离性与并发性能成反比,需要在两者之间权衡,于是就有了事务隔离级别的概念:
读未提交:事务更新数据前增加S锁
读已提交:事务更新数据前增加X锁(避免了脏读)
可重复读:事务更新数据前增加X锁,读取数据前增加S锁(避免脏读,不可重复读)
串行化:事务更新数据前增加X表锁,读取数据前增加S表锁(避免脏读,不可重复读,幻读)
MySQL的InnoDB默认位可重复读级别。
🌈下一节将对MySQL数据优化进行说明,点个赞再走叭!
评论