UPDATE锁表的问题和解决

前几天,有个表锁表了。

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

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

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

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

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

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

也就是说:
当执行

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

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

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

但是很明显:按照现在常规数据库的规范,一般都是自增索引,或者说是无意义的索引(不要用有意义的值当键值),所以基本上不会以主键进行筛选。因为没有实际意义。
最好的情况也是二级索引锁范围(似乎是间隙锁)

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


第二个问题:
执行命令的时候,会断网导致没有上传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;

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


第三个问题:修改不停修改的数据。
这个是有很高风险的。

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

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


版权声明:本文为weixin_45642669原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。