锁对于传统数据库来讲是很是重要的, 里面也掺杂各类权衡, 概念类较多, 本文只针对部份内容作了讲解.mysql
单独给一行数据记录加锁, mysql 中 咱们经常使用的 InnoDB 引擎支持行锁.sql
优点: 是常见关系型数据库中锁粒度最小的一种锁, 可以有效的提升并发操做.数据库
劣势: 消耗更多资源, 用法不规范容易产生死锁bash
顾名思义, 对当前操做的整张表加锁,是目前 mysql 锁粒度最大的一种并发
最多见的 myisam 引擎使用表锁.高并发
InnoDB 引擎 sql 使用不当(如非主键、索引条件)会退化为表锁.性能
优点: 并发读没问题, 消耗资源少, 加减锁速度快, 能够避免死锁.ui
劣势: 大部分状况下DML操做并发低, 频繁对全表加锁, 发生锁冲突的几率很是高.spa
页锁是介于比表锁和行锁之间的一种锁, 只是对数据页进行锁定线程
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但并发低,行级并发高,但耗资源。因此取了折衷的页级,一次锁定数据页中相邻的一组记录
mysql 中的BDB引擎支持页级锁
在 mysql 数据库中, 从全局看, 共分为这两种锁, 但他们的用处有很大区别.
latch 直译过来为“门闩(shuān)”, 相似于下图
它在数据库中的学名叫作 闩锁(一种轻量级的锁), 在 InnoDB 存储引擎中,latch又能够分为 mutex(互斥量)和 rwlock(读写锁), 其目的是用来保证并发线程操做临界资源的正确性,而且一般没有死锁检测的机制.
# 查看关于闩锁的统计信息
SHOW ENGINE INNODB MUTEX ;
+--------+------------------------+---------+
| Type | Name | Status |
+--------+------------------------+---------+
| InnoDB | rwlock: log0log.cc:838 | waits=1 |
+--------+------------------------+---------+
复制代码
lock 锁, 是咱们打交道最多的一种, 它主要针对的是事务,用来锁定的是数据库中的对象,如前面提到的表锁、页锁、行锁。而且通常lock的对象仅在事务 commit 或 rollback 后进行释放(不一样事务隔离级别释放的时间可能不一样)。此外,lock,正如在大多数数据库中同样,是有死锁机制的.
容许事物读取数据
当你拿到了共享锁, 你能够读取这条数据, 另外一我的一样能够拿到共享锁去读取数据(这里咱们称为锁兼容)
可是同时另外一我的也来了, 他同时想要拿排他锁去更新此条数据,那么他必须等待释放共享锁才能够拿到排他锁更新数据(这里咱们称之为锁不兼容)
容许事物删除或更新一行数据
前面咱们举例了 若是别人已经持有共享锁了, 其余人是不能拥有排他锁的.
当一我的拿到此条数据的排他锁, 不能同时再拿到排他锁和共享锁的(锁不兼容).
排他锁(X Lock)和任何锁都不兼容.
咱们知道 当咱们频繁 更新数据 加排他锁 (X Lock) 的时候, 由于其锁的不兼容性, 会严重影响正常的数据查询性能.
一致性的非锁定读 是指 InnoDB 存储引擎经过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。若是读取的行正在执行 DELETE 或 UPDATE 操做,这时读取操做不会所以去等待行上锁的释放。相反地,InnoDB 存储引擎会去读取行的一个快照数据
一致性非锁定读的快照数据实际上是读的 undo 数据(undo是用来回滚事务中的数据), 没有额外的锁操做, 因此读取速度很是的快.
一致性的非锁定读由于不须要等待排他锁 (X Lock) 的释放, 因此极大的提升了并发的性能, 在 innodb 事务隔离级别 不可重复读(read-committed)、可重复读(repeatable-read 默认级别) select 使用的是 一致性的非锁定读.
思考: 一致性的非锁定读 解决了什么问题? 带来了什么问题?
在一些强一致的场景, 咱们是但愿让用户读取到的永远是最新的数据. 这时候, 咱们须要使用 一致性锁定读 的场景.
下面展现了两种基于数据库查询语句上X锁和S锁, 通常与显示的事务组合使用.
SELECT…FOR UPDATE对读取的行记录加一个X锁,其余事务不能对已锁定的行加上任何锁
SELECT…LOCK IN SHARE MODE对读取的行记录加一个S锁,其余事务能够向被锁定的行加S锁,可是若是加X锁,则会被阻塞
FOR UPDATE 也是咱们常常所说的悲观锁, 对应的还有乐观锁, 乐观锁更可能是业务层面的实现, 这里再也不讲述.
死锁是指两个或两个以上的进程在执行过程当中,因为竞争资源或者因为彼此通讯而形成的一种阻塞的现象,若无外力做用,它们都将没法推动下去.
目前主要仍是靠业务逻辑来解决, 若是程序是串行, 就不会产生死锁, 只有并发状况下才有可能产生, 程序并行+数据库并行(行级锁)运行, 可能会发生死锁.
这里可使用此命令查看全部线程, 对应的提示直接 kill 掉便可
show processlist
复制代码
查看目前锁的状况
1:查看当前的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
2:查看当前锁定的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
3:查看当前等锁的事务
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
复制代码
固然你也能够经过配置 innodb_lock_wait_timeout 属性,来指定锁的超时时间, 超时数据库系统自动 kill.
不过若是出现了长时间获取不到锁, 数据库会自动进行死锁检测, 并进行终止.
固然,保证业务中操做数据库的执行顺序, 避免交叉执行, 基本可以避免的死锁状况。
本文一部分参考概念 《mysql 技术内幕》一书.
更多有趣的计算机技术关注 呆呆熊一点通 :