# 删改数据如何避免锁表?

# 什么是锁机制?

平时 MySQL 执行语句的时候,会自动给数据加锁。

InnoDB 采用的是行级锁,删改数据的时候,MySQL 会锁住记录。

image-20200607212441588

比如:上图更新 3 条语句,只会锁住这三条记录。被锁住的记录有什么表现?这需要根据它使用的锁来说明

# 共享锁和排它锁

行级锁分为:

  • 共享锁(S 锁)
  • 排它锁(X 锁)

共享锁和排它锁,**都不允许 **其他事务 执行写操作,但是可以读数据。

排他锁不允许对数据再加另外的锁。

# 共享锁

只有 serializable 事务隔离级别,才会给数据添加共享锁。也可以手动添加共享锁

select ... from ... lock in share mode;
1

事务不提交,该共享锁不会被释放,其他事务只能读取数据,而不能写数据。

如下面的测试

-- 会话 1
-- 开启事物,并查询前 10 条记录
BEGIN;
SELECT
		* 
	FROM
		t_test 
WHERE
	id <= 10 LOCK IN SHARE MODE;
	
-- 先不提交事务,去 会话 2,执行更新操作
COMMIT;


-- 会话 2
-- 开启事物,并执行更新语句
BEGIN;
UPDATE t_test 
	SET `name` = 'abc' 
WHERE
	id <= 10;
-- 会发现更新语句被阻塞了,要等待会话 1 释放共享锁

-- 可以回滚该事务,不让修改生效
ROLLBACK;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 排他锁

MySQL 会 默认 给添加、修改和删除记录,设置排他锁。

手动添加排他锁的语法为

select ... from ... for update;
1

可以对该数据进行查询,但是不能对加了排它锁的数据进行修改。(同时也不能对该数据加排他锁了)

# 如何减少并发操作的锁冲突?

把复杂的 SQL 语句,拆分成多条简单的 SQL 语句。

复杂 SQL 语句执行时间长,锁时间长,拆分成简单的语句,每次锁定数据少,锁时间短