MySQL本身也是在文件系统的基础上发展而来,因为锁的存在使之有所不同。

MySQL作为一种数据库软件,难免会存在对其共享资源的并发访问,为了协调和管理不同资源的并发访问,也就产生了锁机制,因为锁机制的存在为数据库提供了数据的完整性和一致性。

从锁的级别来分锁可分为:行级锁、表级锁、页级锁。
从锁的类型来分锁可分为:共享锁、排它锁(独占锁)。
为了协调行锁、表锁产生了:意向锁(表级锁)。

共享锁,允许事务去读取数据。
排它锁,允许事务去修改或删除数据。
意向锁,获取行级锁的时候,自动添加的表级锁,包含:意向共享锁、意向排它锁。

对于MyISAM存储引擎,只支持表锁,而InnoDB存储引擎则支持行锁、表锁。

MyISAM存储引擎修改、删除数据的时候,会产生排它锁,锁定的整张表,并发写入性能较差,而读取的时候产生的是共享锁,不会锁定表,读取性能就比较好。

InnoDB存储引擎修改、删除数据的时候,会产生排它锁,锁定的特定索引记录,一般不会影响表中的其它行,并发写入性能较好,而读取的时候产生的是共享锁,不会锁定表和行,读取性能较好。

行锁锁定的是索引记录,而不是记录行,如果没有索引,则使用隐式索引进行锁定。

当一张表某些行已经获取了排它锁,在表中会产生一个意向排它锁,如果此时有一个事务要来锁定整张表,那么一看有意向排它锁的存在,该事务就会被阻塞,通过意向锁直接就可以知道能不能锁定表,不需要逐行去遍历检测是否有排它锁,通过意向锁高效地协调了行锁和表锁的关系。

行级锁按照锁定范围来分,又分为三种:

  • Record Lock 单行记录上的锁。
  • Gap Lock 间隙锁,锁定一个范围,不包含记录本身。
  • Next-Key Lock 锁定一个范围,包含记录本身,用于解决幻读问题。

当然,锁也是有利有弊的,也可能出现死锁的情况。
当两个或两个以上的事务在执行过程中,因争夺资源而造成一种相互等待的现象,称为死锁。

最后,也是因为锁的存在,丰富了后续事务的功能。

MySQL通过设计一种机制,使得数据能够完整地从一种一致性状态切换到另一种一致性状态,这种机制称为事务。

事务包含有四大特性:原子性(A)、一致性(C)、隔离性(I)、持久性(D),简称酸性。

  • 原子性:事务中的操作,要么全部成功,要么全部失败,不可切分。
  • 一致性:事务将数据库从一种一致性状态转变成另外一种一致性状态,并且保证数据的完整性。
  • 隔离性:又称并发控制,事务在提交之前对于其它事务是处于不可见的状态的。
  • 持久性:事务一旦提交,结果就是永久性的,不会因为数据库宕机而丢失数据。

原子性、持久性是通过redo日志实现的,一致性是通过undo日志实现的,隔离性是通过锁机制实现的。

从本质上来说,原子性也是为了配合持久性而存在的,当事务的一部分写入redo日志后,发生了崩溃、断电,那么根据原子性来说,该次事务应当恢复,那么对于已经持久化到日志文件中的数据,就必须要通过回溯来撤销。在InnoDB存储引擎中,redo重做日志对应的就是ib_logfile0、ib_logfile1。

接着,事务要进行回滚,那就需要通过一致性来保障,而undo日志就是用来实现一致性的,在undo日志中保存了多个版本的事务的一些信息,通过undo日志,将事务rollback到修改之前的样子。

在此,不得不提的是MySQL的MVCC多版本并发控制,它也是通过undo日志来实现的。
MVCC是通过在每一数据行后头添加2个隐藏字段create version、delete version以及每次开启一个事务会初始化一个事务id。新增一条数据的时候,create version的值就等于事务id,删除数据的时候,delete version就等于事务id,更新数据的时候会先删后增,在undo日志中就会存在2条数据,一条delete version就等于事务id,一条create version的值等于事务id。

在事务执行过程中,可能会同时存在其它的事务,而多个事务之前需要相互隔离,也就是要做到并发控制,锁就是用来实现隔离性的。MySQL的事务的隔离级别包含:Read Uncommitted读未提交、Read Committed读已提交、Read Repeatable可重复读、Serializable串行化。其中,读已提交、可重复读是基于MVCC多版本并发控制来实现的。

锁,为事务的并发控制带来了好处,同时也带来了坏处,包括:脏读、不可重复读、幻读。

脏读,指的是一个事务读到了另一个事务未提交的内容,一旦另一个事务回滚了,就出现了脏数据。
不可重复读,指的是同一个事务使用同一句SQL进行多次读取,返回不同的结果。
幻读,指的是一个事务在进行增删的时候,某些已经确定不会出现的记录突然出现。

要解决脏读,那就需要至少设置隔离级别为:Read Committed读已提交。
要解决不可重复读,那就需要至少设置隔离级别为:Read Repeatable可重复读。
要解决幻读,那就需要设置隔离级别为:Serializable串行化或者采用Next-Key Lock间隙锁。

更多相关文章

  1. MySQL系列多表连接查询92及99语法示例详解教程
  2. Linux下MYSQL 5.7 找回root密码的问题(亲测可用)
  3. MySQL 什么时候使用INNER JOIN 或 LEFT JOIN
  4. android从服务器下载文件(php+apache+win7+MySql)
  5. 【有图】android通过jdbc连接mysql(附文件)
  6. [置顶] android 批量插入数据
  7. Android性能优化-SQLite数据库
  8. android 通过php 连接 mysql
  9. android通过php连接mysql数据库!!!!

随机推荐

  1. 分享一个PHP写的命令行音乐搜索下载器
  2. 关于PHP进程防止内存溢出的排查
  3. php模拟qq登录代码
  4. php base64如何进行URL字符串编码和解码?
  5. PHP实现长轮询【代码示例】
  6. PHP中数组规范和自定义集合
  7. 带你一分钟了解php的四大特性八大优势(详
  8. PHP SPL 标准库之 Countable
  9. PHP之微服务协程框架Swoft
  10. 微信PC端登录和手机端登录逻辑分享