在数据库并发操作场景下,多个事务同时更新同一条数据很容易引发数据不一致问题,行级锁和悲观锁是常用的并发控制手段,能够有效提升SQL数据更新的安全性。

行级锁与悲观锁的核心原理
行级锁的定义
行级锁是数据库锁粒度最小的一种锁机制,它只会锁定需要操作的那一行数据,不会影响到表中其他行的正常读写操作。相比表级锁,行级锁的并发性能更好,适合高并发的更新场景。
悲观锁的定义
悲观锁的核心思想是假设并发冲突发生的概率很高,所以在操作数据之前就先对数据进行加锁,直到当前事务完成提交或者回滚,锁才会被释放,其他事务无法同时操作被锁定的数据。
SQL中使用行级锁与悲观锁的方式
MySQL InnoDB引擎的行级锁使用
InnoDB引擎默认支持行级锁,当执行更新语句时,会自动对符合条件的行加上行级锁,我们可以通过以下示例查看锁的效果:
-- 开启事务 START TRANSACTION; -- 更新id为1的用户余额,此时会自动对id=1的行加行级锁 UPDATE user SET balance = balance - 100 WHERE id = 1; -- 提交事务,释放锁 COMMIT;
悲观锁的实现方式
在SQL中可以通过FOR UPDATE语句实现悲观锁,该语句会对查询到的行加上排他锁,其他事务无法对这些行执行更新、删除操作,也无法加FOR UPDATE锁。
-- 开启事务 START TRANSACTION; -- 查询id为1的用户信息并加悲观锁 SELECT * FROM user WHERE id = 1 FOR UPDATE; -- 执行更新操作 UPDATE user SET balance = balance - 100 WHERE id = 1; -- 提交事务,释放锁 COMMIT;
两种锁机制的使用注意事项
- 行级锁依赖索引,如果更新语句没有使用索引,InnoDB会自动升级为表级锁,反而会降低并发性能,所以更新条件要尽量使用主键或者唯一索引。
- 悲观锁会阻塞其他事务的操作,所以加锁的事务要尽快提交或者回滚,避免长时间持有锁导致其他事务等待超时。
- 悲观锁不适合读多写少的场景,大量读操作加锁会严重影响系统性能,这类场景更适合使用乐观锁。
适用场景对比
我们可以通过下表对比两种锁的适用场景:
| 锁类型 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| 行级锁 | 高并发单行更新场景 | 锁粒度小,并发影响低 | 依赖索引,无索引会升级为表锁 |
| 悲观锁 | 并发冲突概率高的更新场景 | 提前加锁,避免冲突 | 阻塞其他事务,性能开销较高 |
总结
行级锁和悲观锁都是提升SQL数据更新安全性的有效手段,行级锁是InnoDB默认的更新锁机制,适合大多数单行更新场景,而悲观锁通过FOR UPDATE实现,适合并发冲突频繁的场景。开发者需要根据实际的业务场景选择合适的锁策略,同时注意索引使用和事务时长控制,才能既保障数据安全,又不影响系统性能。