先说结论
如果条件中确定使用了索引,则会锁该行,如没有索引或没使用到索引,则会锁表。
是否使用到索引,利用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 KEYgoods_id_UNIQUE
(goods_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
2.使用索引字段验证行锁
先打开两个连接session
1.session1开启事务并修改数据
#session1开启事务
begin;
#执行后不要提交
UPDATEgoods
.goods
SETgoods_num
= '100' WHERE (goods_id
= '1');
#去session2修改该条数据
注:session1此时未提交
2.session2操作,三种场景
a.session2修改该数据
UPDATE
goods
.goods
SETgoods_num
= '100' WHERE (goods_id
= '1');
session2修改当前数据被阻塞,因为修改属于特殊读这里会使用当前读,修改阻塞说明session1事务加了锁。但此时不能判断是行锁还是表锁。
将session1提交后,session2随即成功提交,这里阻塞了20s左右
b.session2修改其他数据
UPDATE
goods
.goods
SETgoods_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;
#执行后不要提交UPDATEgoods
.goods
SETgoods_num
= '100' WHERE (goods_name
= '1');
#去session2修改该条数据
注:session1此时未提交
2.session2操作,三种场景
a.session2修改该数据
UPDATE
goods
.goods
SETgoods_num
= '100' WHERE (goods_name
= '1');
session2修改当前数据被阻塞,因为修改属于特殊读这里会使用当前读,修改阻塞说明session1事务加了锁。但此时不能判断是行锁还是表锁。
将session1提交后,session2随即成功提交,这里阻塞了20s左右
b.session2修改其他数据
UPDATE
goods
.goods
SETgoods_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 KEYgoods_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
SETgoods_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
SETgoods_num
= '100' WHERE (id = '1');
session2修改当前数据被阻塞,但此时不能判断是行锁还是表锁。
将session1提交后,session2随即修改成功,这里阻塞了20s左右
d.session2开启事务后修改其他数据
session2修改其他数据同样被阻塞,说明锁的是表锁,不是行锁。
将session1提交后,session2随即修改成功,这里阻塞了20s左右
网友评论