一、锁的概念
锁是计算机协调多个线程并发访问某一资源的机制;
在数据库中,数据也是一种供许多用户共享的资源,如何保证数据并发的一致性、有效性,是所有数据必须解决的一个问题,锁冲突也是影响数据访问性的一个重要因素。
锁对数据库的性能而言显得尤为重要,也更加复杂。
二、Mysql中的锁
Mysql的锁机制比较简单,其中最显著的特点是不同的存储引擎,锁的机制不一样;
比如:MyISAM和MEMORY存储引擎采用的是表级锁;
InnoDB采用的行级锁,也支持表级锁,但是默认情况下是采用的行级锁。
二、Mysql中的锁的特点
1. 表级锁:
开销小,加锁快,不会出现死锁;锁定力度大,发生锁冲突的概率高,并发度低;
2. 行级锁:
开销大,加锁慢,会出现死锁;锁定粒度小,发生冲突的概率低,并发度高。
3. 页面锁:
开销和加锁时间介于行级锁 和 表级锁之间,会出现死锁;锁定粒度介于行级锁 和 表级锁之间;
4. 使用场景:
表级锁适合于查询为主,只有少量按索引条件更新数据的应用,如OLAP系统;
行级锁则适合于有大量安索引条件并发更新少量不同的数据,同时又有并发查询的应用;
三、MyISAM的表锁
1. 锁的简单介绍:
2. 锁定具体使用:
加锁 lock table 表名 READ
3. 具体事例:
LOCK TABLE demomyisam READ
3.1 先给表加读锁,
结果:
在同一个session和另外的session,都是可以查询的;
在同一个session,不能做插入操作(更新操作也是同样的错误);
(接着2 的操作)在另外的session,执行插入和更新操作(会出现一直等待的情况,知道2中的解锁才行);
解锁操作:unlock tables;
对表 A 加锁,这时候不能创建另外的表;
对表 A 加锁,操作表 B ,同一个 session 执行插入和更新,都会报错(但是报错的信息和上一个是不一样的);
对表 A 加锁,操作表 B,不同的session 执行插入和更新,都不会报错;
mysql的锁,是不支持别名的;比如 加锁 LOCK TABLE demomyisam READ ,按说查询 demomyisam 是不会报错的,但是, SELECT * FROM demomyisam a ,就报错了;(结论:mysql的锁,是不支持别名的),这时候的话,需要这样加锁:LOCK TABLE demomyisam AS a READ
3.2 先给表加写锁
SELECT * FROM demomyisam
四、InnoDb锁详解
1. 行锁:
读作,又称共享锁,当一个事务对某几行上读锁的时候,允许其他的事物对这几行进行读操作,但是不允许其他进行写操作,也不允许其他的事物给这几行上排它锁,但是允许上读锁;
写锁,又称排它锁,当一个事务对某几行上写锁的时候,不允许其他的事物写,但是允许读,更不允许其他的事物给这几个行上任何锁,包括写锁;
2. 加锁操作:
上共享锁语法:lock in share mode
SELECT * FROM 表名 WHERE (需要锁的条件) LOCK IN SHARE MODE;
排它锁语法: for update
SELECT * FROM 表名 WHERE (需要锁的条件)FOR UPDATE;
3. InnoDb 行锁的特点
1.
BEGIN
select * from testdemo where id =1 for update
在另外一个session中
update testdemo set c1 = '1' where id = 2 成功
update testdemo set c1 = '1' where id = 1 等待
2.BEGIN
update testdemo set c1 = '1' where id = 1
在另外一个session中
update testdemo set c1 = '1' where id = 1 等待
3.
BEGIN
update testdemo set c1 = '1' where c1 = '1'
在另外一个session中
update testdemo set c1 = '2' where c1 = '2' 等待
3. 表锁:
和MyISAM差别不大,
注意:开启一个事务的时候会解锁表;
1.先来看下行锁
第一个session中
select * from testdemo where id =1 for update
第二个session
select * from testdemo where id =1 lock in share mode
回到第一个session UNLOCK TABLES 并不会解锁
使用commit 或者 begin或者ROLLBACK 才会解锁
2.再来看下表锁
lock table testdemo WRITE
使用commit,ROLLBACK 并不会解锁
使用UNLOCK TABLES 或者begin会解锁