mysql的存储引擎是底层负责数据存储和提取的组件,不同的存储引擎实现的锁机制存在明显差异,其中表锁和行锁是两种最基础的锁类型,对业务的并发处理能力有直接影响。

表锁和行锁的基本概念
表锁是mysql中粒度最大的锁,在对表执行写操作时会锁定整张表,其他会话对该表的读写操作都会被阻塞,直到锁被释放。表锁的开销小,加锁速度快,但并发度低,适合以查询为主、写操作较少的场景。
行锁是粒度最小的锁,只锁定操作涉及的具体行记录,其他会话可以同时对表中其他行进行读写操作,并发度高,但加锁开销大,加锁速度慢,还可能出现死锁问题,适合写操作频繁、并发要求高的场景。
常见存储引擎对锁的支持情况
mysql中常用的存储引擎包括InnoDB、MyISAM、MEMORY等,它们对表锁和行锁的支持情况如下:
| 存储引擎 | 表锁支持 | 行锁支持 | 默认锁类型 |
|---|---|---|---|
| InnoDB | 支持 | 支持 | 行锁 |
| MyISAM | 支持 | 不支持 | 表锁 |
| MEMORY | 支持 | 不支持 | 表锁 |
InnoDB存储引擎的锁机制
InnoDB是mysql默认的存储引擎,同时支持表锁和行锁,默认使用行锁。InnoDB的行锁是基于索引实现的,如果执行的SQL语句没有使用索引,行锁会升级为表锁,这一点需要特别注意。
以下是InnoDB中行锁的示例,假设有一张用户表user,主键为id:
-- 开启事务 START TRANSACTION; -- 更新id为1的用户,此时会对id=1的行加行锁 UPDATE user SET name = '张三' WHERE id = 1; -- 此时其他事务可以更新id不为1的用户,不会被阻塞 -- 提交事务,释放行锁 COMMIT;
如果上述更新语句的WHERE条件没有使用索引,比如WHERE name = '李四'且name字段没有索引,那么InnoDB会对整张user表加表锁,阻塞其他事务的所有写操作。
MyISAM存储引擎的锁机制
MyISAM存储引擎只支持表锁,不支持行锁。它对表的读操作会加共享表锁,此时其他会话可以读该表但不能写;对表的写操作会加排他表锁,此时其他会话对该表的读写操作都会被阻塞。
MyISAM的表锁示例:
-- 对user表加共享表锁,其他会话可以读但不能写 LOCK TABLES user READ; -- 执行查询操作 SELECT * FROM user WHERE id = 1; -- 释放表锁 UNLOCK TABLES; -- 对user表加排他表锁,其他会话读写都会被阻塞 LOCK TABLES user WRITE; -- 执行更新操作 UPDATE user SET name = '王五' WHERE id = 2; -- 释放表锁 UNLOCK TABLES;
如何选择合适的存储引擎
如果业务场景以查询为主,写操作很少,且对并发要求不高,可以选择MyISAM存储引擎,它的表锁机制开销小,性能表现更好。如果业务写操作频繁,需要高并发支持,那么应该选择InnoDB存储引擎,利用行锁提升并发处理能力,同时需要注意为查询和更新语句建立合适的索引,避免行锁升级为表锁。
另外需要注意,InnoDB的行锁在事务中才会生效,如果没有开启事务,执行单条更新语句时,mysql会自动提交事务,行锁的持有时间很短,一般不会对并发造成太大影响。如果需要长时间持有行锁,需要手动开启事务并在操作完成后提交。