锁:协调并发访问、存储引擎支持不同的锁机制
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。查询为主,web应用
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。大量索引,OLTP
OLTP:事物处理,用在实时性高的地方
OLAP:分析处理,历史数据的整体分析
MyISAM表锁:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)
写锁:lock table mylock write;只有持有锁的线程可以对表进行更新操作直到unlock tables;
读锁:lock table mylock read;所有线程都可以读取,但是都不可以修改。并且加了锁的还不可以访问没加锁的表。其他session可以进行插入操作,但是更新会阻塞直到unlock tables。但是如果用的是lock table mylock read local加了一个local(只在本地的意思,就是只在加锁的线程)并发执行,就没加读锁的可以进行修改,只是加了读锁的在unlock tables前不能访问到修改。
MyISAM在执行查询语句之前,会自动给涉及的所有表加读锁,在执行更新操作前,会自动给涉及的表加写锁
mysql> show status like ‘table%’;
Table_locks_immediate | 352 锁立即执行时间
Table_locks_waited | 2 锁等待时间
InnoDB行锁
A 原子性,通过undo实现
C 最终保证一致性
I 隔离性,通过锁机制实现
D 持久性,通过redo实现
并发事务带来的问题:
脏读:一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”
不可重复读:一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。
幻读: 一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”
上述出现的问题都是数据库读一致性的问题,可以通过事务的隔离机制来进行保证。
共享锁(s):读锁。允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(x):写锁。允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。
1.不是索引默认锁的是表锁
2.用了索引,锁的就是行
3.一个索引对应多行记录会出现阻塞状态,就是select * from tab_with_index where id = 1 and name=‘1’ for update和select * from tab_with_index where id = 1 and name=‘4’ for update会有冲突
总结
对于MyISAM的表锁,主要讨论了以下几点:
(1)共享读锁(S)之间是兼容的,但共享读锁(S)与排他写锁(X)之间,以及排他写锁(X)之间是互斥的,也就是说读和写是串行的。
(2)在一定条件下,MyISAM允许查询和插入并发执行,我们可以利用这一点来解决应用中对同一表查询和插入的锁争用问题。
(3)MyISAM默认的锁调度机制是写优先,这并不一定适合所有应用,用户可以通过设置LOW_PRIORITY_UPDATES参数,或在INSERT、UPDATE、DELETE语句中指定LOW_PRIORITY选项来调节读写锁的争用。
(4)由于表锁的锁定粒度大,读写之间又是串行的,因此,如果更新操作较多,MyISAM表可能会出现严重的锁等待,可以考虑采用InnoDB表来减少锁冲突。
对于InnoDB表,本文主要讨论了以下几项内容:
(1)InnoDB的行锁是基于索引实现的,如果不通过索引访问数据,InnoDB会使用表锁。
(2)在不同的隔离级别下,InnoDB的锁机制和一致性读策略不同。
在了解InnoDB锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁,包括:
- 尽量使用较低的隔离级别; 精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会;
- 选择合理的事务大小,小事务发生锁冲突的几率也更小;
- 给记录集显式加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁;
- 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会;
- 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响; 不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁;
- 对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能。