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。如果你在锁定表时使用了别名,那么在后续的查询和更新操作中也必须使用相同的别名,否则会导致操作失败。

image-20240818174058465

因此:

锁分配的优先级: 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:间隙锁+右记录锁。

image-20240817163233502

锁的机制非常复杂,可以深入了解的地方。

posted @ 2024-08-18 23:55  七七喜欢你  阅读(132)  评论(0编辑  收藏  举报