select ...... from ... for update是否会锁表?

        今天看到了一篇文件,讲到select xx form xx for update是会索表还是会锁行的问题?给我的第一个感觉就是这个还要验证吗。肯定是锁行啊,怎么可能会索表,经过验证之后就被打脸了,要看它加的是行锁或者表锁,需要看sql在执行的过程中是不是用了主键或索引,如果用了主键或索引,加的就是行锁,否则就是表锁。

        我们这里在mysql5.7上验证一下,先创建一张用户表t_org_user有三个字段的表,分别是id、name、number三个字段,其中id为主键自增序列,number为索引。建表语句以及本案例中需要用到的sql如下:

//建表sql
create table  if not exists t_org_user(
id bigint(30) not null auto_increment,
number varchar(255) not null default '',
name varchar(255) not null default '',
primary key(id),
key(number) using btree)
engine=innodb auto_increment=1 default charset=utf8mb4;
//插入数据sql
insert into t_org_user(number,name) values('001','张三');
insert into t_org_user(number,name) values('002','赵四');
insert into t_org_user(number,name) values('003','王五');
insert into t_org_user(number,name) values('006','赵六');
//查看表结构sql
show create table t_org_user \G;
//检查sql是否走索引
explain select * from t_org_user where id = 1;
//检查事务是否自动提交sql
show variables like '%commit%';
//设置事务手动提交
set autocommit = 0;
//手动加悲观锁
select * from t_org_user where id = 1 for update;
//更新字段sql
update t_org_user set name = '李四' where number = '002';

        开启场景验证之前需要先插入几条数据,执行上述sql中的insert语句。由MySQL默认事务都是自动提交的,在做这种场景验证的时候,需要将自动提交事务关闭掉改为手动提交,对应的sql命令为set autocommit = 0。该指令是会话级别的,也就是如果重新开一个mysql命令行窗口就要执行set autocommit =0指令,从而将事务由自动提交改为手动提交。开启两个mysql命令行窗口做场景演示,假设分别命名为窗口1和窗口2.

场景一:验证走主键约束是锁表还是锁行

        验证场景之前首先要把对应的会话的事务自动提交关闭掉。

          1.在窗口1中执行sql: select * from t_org_user where id = 1 for update;

          2.在窗口2中执行sql:update t_org_user set name = '张三1' where id = 1;失败,提示”Lock wait timeout exceeded; try restarting transaction“错误。

            3.在窗口2中先将事务回滚掉再执行sql:update t_org_user set name = '李四2' where id = 2;执行成功

         通过场景1的验证,我们可以得出结论,如果是走主键索引,加的是行级锁。

场景二:验证走约束是锁表还是锁行

        验证场景之前首先要把对应的会话的事务自动提交关闭掉。

          1.在窗口1中执行sql: select * from t_org_user where number = '001' for update;

          2.在窗口2中执行sql:update t_org_user set name = '张三1' where id = 1;失败,提示”Lock wait timeout exceeded; try restarting transaction“错误。

            3.在窗口2中先将事务回滚掉再执行sql:update t_org_user set name = '李四' where id = 2;执行成功

         通过场景2的验证,我们可以得出结论,如果是走的是约束索引,加的是行级锁。

场景三:验证不走主键约束或普通约束是锁表还是锁行

        验证场景之前首先要把对应的会话的事务自动提交关闭掉。

          1.在窗口1中执行sql: select * from t_org_user where name = '张三' for update;

          2.在窗口2中执行sql:update t_org_user set name = '张三1' where id = 1;失败,提示”Lock wait timeout exceeded; try restarting transaction“错误。

            3.在窗口2中先将事务回滚掉再执行sql:update t_org_user set name = '李四2' where id = 2;执行提示”Lock wait timeout exceeded; try restarting transaction“错误。

             4.在窗口2中先将事务回滚掉再执行sqlinsert into t_org_user        (number,name)values('005','洪七');执行失败。提示”Lock wait timeout exceeded; try restarting transaction“错误。

         通过场景三的验证,我们可以得出结论,如果是不走主键或普通约束,加的是表级锁。

你可能感兴趣的:(sql,数据库,mysql)