MySQL锁有哪些??
1.MySQL锁有哪些? 什么是间隙锁?
从锁的粒度来区分:
1.行锁
加锁粒度比较小,但是资源开销比较大。InnoDB支持。
优点是锁定颗粒度很小,所以发生锁定资源争用的概率也最小,因此在在并发处理能力上面有较大的优势。
缺点是由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了,比页级锁和表级锁消耗更多的内存。此外,行级锁定也最容易发生死锁。
-
共享锁(读锁):多个事务可以对同!a一个数据共享同一把锁。持有锁的事务可以访问数据,但是只能读不能修改。
select xxx lock in share mode
比较简单;
-
排他锁(写锁):只有一个事务可以获得排他锁,其他事务都不能获取该行的锁。Innodb会对update 、delete、insert自动添加排他锁。
使用begin开启事务,不关闭事务,因为提交事务或回滚事务就会释放锁。
select xxx for update
注:排他锁的启用,除了for update 外还有insert,update, delete
打开另一个查询窗口,对同一数据分别使用排他查和共享锁查询两种方式查询;
第一个窗口:
begin;
select * from t1 where a=1 for update;
-- 排他锁
第二个窗口:
select * from t1 where a=1 for update;
select * from t1 where a=1 lock in share mode;
第一个窗口运行之后,第二个加锁会进行阻塞。然后一直在等待。
但是普通查询是成功的。
因为排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁 ,但是普通查询可以,因为普通查询默认不加任何锁。
但查到的数据是修改数据之前的老数据
ps总结:一个线程进行了加排他锁,其他线程不能进行加共享或排他锁。但是普通查询可以进行读取修改前的数据。
1.select语句默认不会加任何锁类型
2.排他锁指的是一个事务在一行数据加上排他锁后,其他事务不能再在其上加其他的锁,但可以直接通过select ...from...查询数据,因为普通查询没有任何锁机制。
- 自增锁:通常针对Mysql中的自增字段,保证自增字段不会冲突。如果有事务回滚的情况,数据会回滚,但是自增序列不会回滚。
2.表锁(可以同时读,写不行)
加锁粒度大,加锁资源开销比较小。MyIsam和Innodb都支持。
- 表共享读锁:
用法: LOCK TABLE table_name [ AS alias_name ] READ
指定数据表,LOCK类型为READ即可,AS别名是可选参数,如果指定别名,使用时也要指定别名才可
而且一旦加锁,无法进行插入数据和修改数据。
CREATE table t1(
a INTEGER not null,
b INTEGER not null
);
UNLOCK tables;
lock table t1 as tone read;
insert into t1 VALUES(1,3);
-- > 1100 - Table 't1' was not locked with LOCK TABLES
select * from t1;
-- > 1100 - Table 't1' was not locked with LOCK TABLES
select * from t1 as tone;
-- 得到结果
update t1 set a=0 where a=1
-- > 1100 - Table 't1' was not locked with LOCK TABLES
update t1 as tone set a=0 where a=1
-- > 1099 - Table 'tone' was locked with a READ lock and can't be updated
UNLOCK tables;
lock table t1 read;
select * from t1;
综上所述,设定读锁之后就不能再进行插入和修改操作。
如果在加锁的时候使用了别名,那么select读数据的时候也需要别名才能读出数据。
如果没加别名进行的上锁操作,那么都可以直接读。
- 表排他写锁:对MyISAM表的写操作,则会阻塞其他用户对同一表的读写操作。
用法: LOCK TABLE table_name [AS alias_name] [ LOW_PRIORITY ] WRITE
别名用法与读锁一样,写锁增加了指定优先级的功能,加入LOW_PRIORITY可以指定写锁为低优先级。
CREATE table t2(
a INTEGER not null,
b INTEGER not null
);
UNLOCK tables;
lock table t2 as ttwo write;
select * from t2 as ttwo;
TRUE;
select * from t2;
FALSE;
update t2 as ttwo set a=0 where a=1
TRUE;
update t2 set a=0 where a=1
FALSE;
在上锁的情况下,使用别名和不使用别名的区别并不在于是否有别名,而在于锁的作用范围和查询的上下文。
当你对表 t2
使用别名 ttwo
进行锁定时,所有对 t2
的操作都必须使用这个别名 ttwo
。如果你在锁定表时使用了别名,那么在后续的查询和更新操作中也必须使用相同的别名,否则会导致操作失败。
因此:
锁分配的优先级: LOW_PRIORITY WRITE < READ < WRITE
申请锁时使用别名,使用锁定表时必须加上别名
原因:
1.有可能不能操作(查询或更新)没有被锁定的表。
例如当只申请table1的读锁,SQL语句中包含申请的表的话,那么对table2的操作是非法的。例如:
lock table t1 read;
SELECT * from t2
false;
reason:错误的上锁。
2.能在一个SQL中使用两次表(除非使用别名)
当SQL语句中多次使用一张表时,系统会报错。例如:
select * from t1 where a in(select a from t1)
多次使用一个表的话,需要声明多个别ming。
unlock tables;
lock table t1 as tone read,t1 as ttwo read;
select * from t1 as tone where a in (select a from t1 as ttwo);
- 意向锁:Innodb自动添加的一种锁,不需要用户干预。
3.页级锁 pagelevel
页级锁是 MySQL 中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。因此,采取了折衷的页级锁,一次锁定相邻的一组记录。
页级锁定和行级锁定一样,会发生死锁。
4.全局锁
flush tables with read lock 加锁之后整个数据库都处于只读状态,所有数据变更操作都会被挂起。一般用于全局备份的时候。
参考文章:
https://blog.csdn.net/weixin_38316697/article/details/106546202
常见的锁算法
user :userid(1.4.9) update user set xxx where userid=5;
1.记录锁: 锁一条具体的数据。
2.间隙锁:RR隔离级别下,会加间隙锁。锁一定的范围,不锁具体的记录。
3.Next-key:间隙锁+右记录锁。
锁的机制非常复杂,可以深入了解的地方。
本文来自博客园,作者:七七喜欢你,转载请注明原文链接:https://www.cnblogs.com/EternalX/p/18366411