直接上干货!(都是比较基础的部分,建议对比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数据优化进行说明,点个赞再走叭!