事务/forupdate会锁表吗

2020-06-29  本文已影响0人  sizuoyi00

先说结论

如果条件中确定使用了索引,则会锁该行,如没有索引或没使用到索引,则会锁表。
是否使用到索引,利用trace工具判断,这里不做叙述。
建议用主键做索引验证

事务验证

1.表结构

CREATE TABLE goods (
id int(11) NOT NULL,
goods_id varchar(45) DEFAULT NULL,
goods_name varchar(45) DEFAULT NULL,
goods_num varchar(45) DEFAULT NULL,
remark varchar(45) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY goods_id_UNIQUE (goods_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

2.使用索引字段验证行锁

先打开两个连接session

1.session1开启事务并修改数据

#session1开启事务
begin;
#执行后不要提交
UPDATE goods.goods SET goods_num = '100' WHERE (goods_id = '1');
#去session2修改该条数据

注:session1此时未提交

2.session2操作,三种场景

a.session2修改该数据

UPDATE goods.goods SET goods_num = '100' WHERE (goods_id = '1');

session2修改当前数据被阻塞,因为修改属于特殊读这里会使用当前读,修改阻塞说明session1事务加了锁。但此时不能判断是行锁还是表锁。

将session1提交后,session2随即成功提交,这里阻塞了20s左右

b.session2修改其他数据

UPDATE goods.goods SET goods_num = '200' WHERE (goods_id = '2');

session2修改其他数据正常执行,说明锁的是行锁,不是表锁。

c.session2查询该数据

SELECT * FROM goods.goods where goods_id = 1;

session2查询操作正常,因为普通读时由于mysql的mvcc机制会使用的是快照度,所以不会阻塞。
mvcc当前读与快照读及其相关原理这里不做叙述

3.使用非索引字段

1.session1开启事务并修改数据

#session1开启事务
begin;
#执行后不要提交UPDATE goods.goods SET goods_num = '100' WHERE (goods_name = '1');
#去session2修改该条数据

注:session1此时未提交

2.session2操作,三种场景

a.session2修改该数据

UPDATE goods.goods SET goods_num = '100' WHERE (goods_name = '1');

session2修改当前数据被阻塞,因为修改属于特殊读这里会使用当前读,修改阻塞说明session1事务加了锁。但此时不能判断是行锁还是表锁。

将session1提交后,session2随即成功提交,这里阻塞了20s左右

b.session2修改其他数据

UPDATE goods.goods SET goods_num = '100' WHERE (goods_name = '2');

session2修改其他数据被阻塞,说明锁的是表锁,不是行锁。

将session1提交后,session2随即成功提交,这里阻塞了20s左右

c.session2查询该数据

SELECT * FROM goods.goods where goods_name = '1';

session2查询操作正常,因为普通读时由于mysql的mvcc机制会使用的是快照度,所以不会阻塞。
mvcc当前读与快照读及其相关原理这里不做叙述

加锁for update验证

注:for update只有在begin commit,也就是事务之间才会起作用,如果发现两个session都成功对一条数据加锁成功,注意看下是否有没有开启事务。

1.表结构

CREATE TABLE goods (
id int(11) NOT NULL,
goods_id varchar(45) DEFAULT NULL,
goods_name varchar(45) DEFAULT NULL,
goods_num varchar(45) DEFAULT NULL,
remark varchar(45) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY goods_id_UNIQUE (goods_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

2.使用索引字段验证行锁

先打开两个连接session

1.session1开启事务后查询加锁

#session1开启事务
begin;
#执行后不要提交
SELECT * FROM goods.goods where id = 1 for update;

注:session1此时未提交

2.session2操作,四种场景

a.session2开启事务后查询当前数据加锁

begin;
SELECT * FROM goods.goods where id = 1 for update;

由于session1加了锁,session2查询加锁被阻塞,但此时不能判断是行锁还是表锁。

将session1提交后,session2随即成功加锁,这里阻塞了20s左右

b.session2开启事务后查询其他数据加锁

begin;
SELECT * FROM goods.goods where id = 2 for update;

session2加锁其他数据正常执行,说明锁的是行锁,不是表锁。

c.session2开启事务后修改该数据

SELECT * FROM goods.goods where goods_id = 1;

session2修改当前数据被阻塞

d.session2开启事务后修改其他数据

UPDATE goods.goods SET goods_num = '100' WHERE (id = '2');

session2修改其他数据正常执行

3.使用非索引字段

1.session1开启事务并修改数据

#session1开启事务
begin;
SELECT * FROM goods.goods where goods_name = 1 for update;

注:session1此时未提交

2.session2操作,四种场景

a.session2开启事务后查询当前数据加锁

SELECT * FROM goods.goods where id = 1 for update;

由于session1加了锁,session2查询加锁被阻塞,但此时不能判断是行锁还是表锁。

将session1提交后,session2随即加锁成功,这里阻塞了20s左右

b.session2开启事务后查询其他数据加锁

SELECT * FROM goods.goods where id = 2 for update;

session2加锁其他数据也被阻塞,说明锁的是表锁,不是行锁。

将session1提交后,session2随即加锁成功,这里阻塞了20s左右

c.session2开启事务后修改该数据

UPDATE goods.goods SET goods_num = '100' WHERE (id = '1');

session2修改当前数据被阻塞,但此时不能判断是行锁还是表锁。

将session1提交后,session2随即修改成功,这里阻塞了20s左右

d.session2开启事务后修改其他数据

session2修改其他数据同样被阻塞,说明锁的是表锁,不是行锁。

将session1提交后,session2随即修改成功,这里阻塞了20s左右

上一篇 下一篇

猜你喜欢

热点阅读