锁是计算机协调多个进程或线程并发访问某一资源的机制,相对其他数据库而言,Mysql的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如Myisam和Memory存储引擎采用的是表级锁;BDB存储引擎采用的是页面锁,但也支持表级锁;Innodb存储引擎既支持行级锁也支持表级锁;以下是他们各自锁的区别:
表级锁:开销小,加锁快;不会出现死锁;锁粒度大.发生锁冲突概率最高,并发度最低.
行级锁:开销大,加锁慢;会出现死锁,锁粒度最小;发生锁冲突概率最高,并发度也最高.
页面锁:开销和加锁时间界于表锁和行锁之间,会出现死锁;锁粒度界于表锁和行锁之间.
1.Myisam 锁问题:
查询表级锁争用情况:
table_locks_waited table_locks_immediate
如果值较高,说明存在着严重的争锁情况.
表级锁的锁模式: 共享锁和排他锁.两锁之间是冲突的,知道锁线程释放.
在执行select前会自动为表加锁,使表具备只读,执行update/insert/delete 会自动为表加排他锁;
mysql不支持锁升级,也就是说显示加锁后,只允许访问加锁的表,隐式加锁也一样.
并发插入:在一定条件下.mysql支持查询与插入一同操作.
允许并发插入相关参数设置:concurrent_insert = 0/1/2
0:不允许并发插入.
1:当有记录从该表删除时,表中有空洞才允许并发插入.
2:不管有无空洞,都允许并发插入.
查看表是否有空洞:show table status like 'table_name';
Data_free: 这一项则表示delete删除记录后是否有空隙.
Myisam的锁调度:
默认情况下,写进程优先获得锁.即使读请求在写请求队列前,写请求也会优先获得锁.
2:Innodb锁问题:
事务的ACID属性:
A:原子性,指事务是一个原子操作单元,其对数据的修改,要么全部执行成功,要么全部不执行.
C:一致性,在事务开始和结束时.数据都必须保持一致状态,这意味着所有数据规则都必须应用于事务的修改,以保证事务的完整性.事务结束时,所有内部数据(如:索引)都必须正确.
I:隔离性,提供一定的隔离机制,保证事务在不受外部并发操作影响的"独立"环境下执行,事务与事务之间是不可见的.
D:持久性,事务完成之后,它对事务的修改是永久性的.即使出现系统的故障也能保持.
相关事务的例子:可以想象一下银行转账.
获取Innodb行锁争用情况:
innodb_row_lock_waits innodb_row_lock_time_avg
Innodb 是通过给索引的索引项加锁来实现的.这意味着Innodb只使用索引来检索数据才会使用行锁,否则使用表锁.
大家又可以想象,因为Innodb是为索引加锁,所以如果两个事务使用同一个索引的话,已然会出现锁等待问题.
即使条件中使用了索引,但mysql的执行计划认为全表扫描的效率高,则会放弃使用索引,所以在分析锁冲突时不要忘记分析sql计划.
Explain Query; 我们也可以强制mysql使用索引 force index 'index_name'.
间隙锁:
为范围的条件值加锁,尽管条件并不存在,避免产生幻读.
例: select * form table_name where id > 100;
那么Innodb会为大于100的索引项加锁,尽管没有101,102....
尽管请求一个不存在的记录时,Innodb也会为这个不存在的值索引加锁.
在一个事务未提交前,其他并发事务不能插入满足其锁定条件的任何记录,也就是不允许出现幻读.