锁表

前几天,有个表锁表了。

数据库是ORACLE,执行的语句是:

select * from t1 where a=1 for update;
update t1 set a =2 where a =1;

执行这两个语句的时候,一个是锁表,一个是误操作。

问题所在

  1. 开启了事务,然后执行了select for update强制加锁
  2. 没有及时释放事务,导致这个字段无法被查询
  3. 当无法获得锁的时候,其他的sql会锁定,进入到等待状态

 

不命中索引导致的锁表

经过查询,mysql的说法比较奇怪:

当执行的时候显式指定主键,则锁主键;如果没有指定主键,如果是二级索引,那么锁一定范围的数据。
如果没有索引,则锁全表。

逻辑上:如果是INNODB模式,肯定会维护一个主键索引。

当执行

select * from t1 where a=%张’ for update;

由于不是主键,所以基本上会锁一定范围的数据。如果没有索引或者不走索引,锁全表。

ORACLE基本上也是一样的:

  • 如果不指定主键则锁全表。
  • 如果是二级索引,那么锁一定范围的数据。
  • 如果是主键,只锁指定行。
  • 没有查到该条数据,则不锁表。


 

  • 假如命中的是热点sql或者字典表,问题就大了
  • 如果命中的是多个数据,那么被查询到的的所有数据会被锁
  • 如果是RR级别,会加入间隙锁,插入数据命中这个范围的也会被锁

锁全表的话:
无法进行新增或者更新操作,所有新增和更新会等待锁释放。
所以会影响正常事务的运行。


commit没有及时提交

执行命令的时候,会断网导致没有上传COMMIT或者ROLLBACK

也就是说:当程序执行如下SQL的时候:

start transaction
select * from t1 where a=1 for update;
update t1 set a =2 where a =1;
commit;

由于系统断网,只上传了两个命令:

start transaction
select * from t1 where a=1 for update;

然后,这个事务就挂着事务把全表给锁了。


同时多表联查的select执行update。

这个是有很高风险的。

一个是:UPDATE会锁INSERT和UPDATE两个语句,而不是单锁UPDATE。

如果说UPDATE的时候按照二级主键进行加锁,而数据一个在表头一个在表位,或者新增的数据正好在间隙之间,就会锁表。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐