MySQL锁
前言
锁是计算机协调多个进程或线程并发访问某一资源的机制,为了解决资源竞争问题。
在数据库中,除了传统的计算资源(如CPU、RAM、I/O等)的争用之外,数据也是一种可供多用户共享的资源,必须解决访问的一致性和有效性,锁冲突也是影响数据库并发访问性能的一个重要因素,锁对数据库而言显得尤为重要,也更加复杂。
基本锁类型
读锁(共享锁)
针对同一个资源,可以同时进行多个读操作。
写锁(互斥锁)
针对同一个资源,一旦加上写锁后,会阻塞其他的读操作和写操作。
MySQl的锁
显示加锁
可以显示的针对表添加读锁或写锁,命令格式:
lock table tableName read,tableName2 write;
查看锁状态
show open tables;
mysql> show open tables;
+--------------------+---------------------------+--------+-------------+
| Database | Table | In_use | Name_locked |
+--------------------+---------------------------+--------+-------------+
| mysql | table_stats | 0 | 0 |
| mysql | collations | 0 | 0 |
| test | myisam_lock | 1 | 0 |
+--------------------+---------------------------+--------+-------------+
In_use 0是为加锁,1是加锁了。
分析锁状态
mysql> show status like 'table_locks%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Table_locks_immediate | 22 |
| Table_locks_waited | 0 |
+-----------------------+-------+
2 rows in set (0.17 sec)
table_locks_immediate
: 表示立即释放表锁数。
table_locks_waited
: 表示需要等待的表锁数。此值越高则说明存在着越严重的表级锁争用情况。
表锁
顾名思义,对整张表进行加锁,MyIsam引擎采用的就是表锁。
表锁的优势:开销小;加锁快;无死锁
表锁的劣势:锁粒度大,发生锁冲突的概率高,并发处理能力低
-
应用场景
InnoDB默认采用行锁,在未使用索引字段查询时升级为表锁。MySQL这样设计并不是给你挖坑。它有自己的设计目的。
即便你在条件中使用了索引字段,MySQL会根据自身的执行计划,考虑是否使用索引(所以explain命令中会有possible_key 和 key)。如果MySQL认为全表扫描效率更高,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划,以确认是否真正使用了索引。
第一种情况:全表更新。事务需要更新大部分或全部数据,且表又比较大。若使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间锁等待和更多的锁冲突。
第二种情况:多表查询。事务涉及多个表,比较复杂的关联查询,很可能引起死锁,造成大量事务回滚。这种情况若能一次性锁定事务涉及的表,从而可以避免死锁、减少数据库因事务回滚带来的开销。
共享读锁
对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读操作,但会阻塞对同一表的写操作。只有当读锁释放后,才能执行其他进程的写操作。在锁释放前不能取其他表。
独占写锁
对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作。在锁释放前不能写其他表。
行锁
对某个记录行进行加速。可以针对表添加读锁或写锁;innodb引擎默认用的就是行锁。
行锁的劣势:开销大;加锁慢;会出现死锁
行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
注:这里通过修改
autocommit
来实现展示模拟锁
共享锁
共享锁,也称读锁,多用于判断数据是否存在,多个读操作可以同时进行而不会互相影响。当如果事务对读锁进行修改操作,很可能会造成死锁。
排他锁
排他锁,也称写锁,独占锁,当前写操作没有完成前,它会阻断其他写锁和读锁。
间隙锁
当我们用范围条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做”间隙(GAP)”。InnoDB也会对这个”间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
危害:若执行的条件是范围过大,则InnoDB会将整个范围内所有的索引键值全部锁定,很容易对性能造成影响
行锁变表锁
如果索引失效的话会导致行锁变表锁。
页锁
开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发处理能力一般。
结论
innodb 存储引擎由于东现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更高一些,但是在整体并发处理能力方面要远远优于 MyISAM 的表级锁定的。当系统并发里较高的时候, Innodb 的整体性能和 MyISAM 相比就会有比较明显的优势了。但是, Innodb 的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让 Innodb 的整体性能表现不仅不能比 MylsAM 高甚至可能会更差。