标签:style blog http tar ext com
MySQL锁
不同的存储引擎支持不同的锁:
3种锁类型:
1、MyISAM表锁
1)查询表锁争用情况
show status like ‘table%‘; --Table_locks_waited值比较高则说明存在严重的表锁争用
2)表锁的锁模式
3)表锁兼容性
4)如何加表锁
隐式加锁:MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行更新(增、删、改等)操作前,会自动给涉及的表加写锁。
显示加锁:(只能访问显示加锁的这些表,不能访问未加锁的表)
- lock table tablename1 read/write [local], tablename2 read/write [local];
- unlock tables;
- lock table tablename as t; --当表存在别名时,同时个别名也要加锁
5)并发插入控制
变量concurrent_insert控制并发插入行为:
- 0:不允许插入
- 1:如果myisam表中没有空洞(即表的中间没有被删除的行),允许在一个进程读表的同时,另一个进程从表尾插入记录。默认
- 2:无论myisam表中有没有空洞,都允许在表尾并发插入记录
6)MyISAM锁调度
相关参数:max_write_lock_count
2、InnoDB行锁
1)InnoDB相对MyISAM最大的不同
2)并发事务处理带来的问题
例如:
张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
与此同时,
事务B正在读取张三的工资,读取到张三的工资为8000。
随后,
事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
最后,
事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。
例如:
在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
与此同时,
事务B把张三的工资改为8000,并提交了事务。
随后,
在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。
例如:
目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
此时,
事务B插入一条工资也为5000的记录。
这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。
理解:
- 不可重复读的重点是修改:同样的条件,你读取过的数据,再次读取出来发现值不一样了
- 幻读的重点在于新增或者删除:同样的条件,第1次和第2次读出来的记录数不一样
从总的结果来看, 似乎两者都表现为两次读取的结果不一致。但如果你从控制的角度来看, 两者的区别就比较大:
- 对于前者, 只需要锁住满足条件的记录
- 对于后者, 要锁住满足条件及其相近的记录
3)事务隔离级别(ISO/ANSI SQL92定义)
注:不同数据库实现不一致
4)获取innodb行锁争用情况
show stauts like ‘innodb%‘;
5)InnoDB行锁模式
- 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
- 排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁:
- 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
- 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
6)InnoDB行锁模式兼容性列表
如果一个事务请求的锁模式与当前的锁兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁:
7)InnoDB行锁实现方式
InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB将使用表锁!在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。
8)间隙锁(Next-Key锁)
当用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。举例假如emp表中只有101条记录,其empid的值分别是 1,2,...,100,101,下面的SQL:
Select * from emp where empid > 100 for update;
--是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也对empid大于101(这些记录并不存在)的“间隙”加锁。
InnoDB使用间隙锁的目的:
在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待。因此,在实际应用开发中,尤其是并发插入比较多的应用, 要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。
InnoDB除了通过范围条件加锁时使用间隙锁外,如果使用相等条件请求给一个不存在的记录加锁,InnoDB也会使用间隙锁!
9)什么时候使用表锁
对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁:
当然,应用中这两种事务不能太多,否则,就应该考虑使用MyISAM表了。
在InnoDB下,使用表锁要注意以下两点。
SET AUTOCOMMIT=0; --如果需要写表t1并从表t2读
LOCK TABLES t1 WRITE, t2 READ, ...;
[do something with tables t1 and t2 here];
COMMIT;
UNLOCK TABLES;
10)死锁
(定义:两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去)
MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了在InnoDB中发生死锁是可能的。
发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并回退,另一个事务获得锁,继续完成事务。但在涉及外部锁,或涉及表锁的情况下,InnoDB并不能完全自动检测到死锁,这需要通过设置锁等待超时参数innodb_lock_wait_timeout来解决。这个参数不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖跨数据库。通过设置合适的锁等待超时阈值,可以避免这种情况发生。
通常来说,死锁都是应用设计的问题,通过调整业务流程、数据库对象设计、事务大小,以及访问数据库的SQL语句,绝大部分死锁都可以避免:
如果出现死锁,可以用:show engine innodb status\G 命令来确定最后一个死锁产生的原因。
其他mysql锁相关命令
1)show processlist;
show processlist显示哪些线程正在运行。您也可以使用mysqladmin processlist语句得到此信息。如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程(也就是,与您正在使用的MySQL账户相关的线程)。如果有线程在update或者insert 某个表,此时进程的status为updating 或者 sending data。
show processlist;只列出前100条,如果想全列出请使用:show full processlist;
2)show open tables;
这条命令能够查看当前有那些表是打开的。In_use列表示有多少线程正在使用某张表,Name_locked表示表名是否被锁,这一般发生在Drop或Rename命令操作这张表时。所以这条命令不能帮助解答我们常见的问题:当前某张表是否有死锁,谁拥有表上的这个锁等。
资料:
标签:style blog http tar ext com
原文地址:http://www.cnblogs.com/yezhaohui/p/3785513.html