数据库里怎么弄悲观锁,设置方法和操作步骤全解析
- 问答
- 2026-01-25 14:42:39
- 36
关于在数据库里怎么弄悲观锁,它的核心思想很简单,我先用,谁也别动”,当你觉得一条数据很可能被别人同时修改时,你就在操作它之前,先把它“锁”上,等你自己的事情全部做完、确认无误后,再放开锁,这样其他想动这条数据的人就只能等着,下面以最常见的MySQL数据库为例,详细说明设置方法和操作步骤。

第一步:理解悲观锁依赖的基础——事务
悲观锁不是单独存在的,它必须和数据库的“事务”一起使用,你可以把事务理解为一个不可分割的工作包,里面的所有操作要么全部成功,要么全部失败,不会只做一半,在数据库里,你通常用 START TRANSACTION; 或者 BEGIN; 来开始一个事务,用 COMMIT; 来提交所有更改,用 ROLLBACK; 来回滚、取消所有更改,悲观锁就在这个事务过程中生效。

第二步:掌握核心的加锁语句——SELECT ... FOR UPDATE 这是实现悲观锁最常用的方法,它不是一条独立的锁命令,而是在你查询数据时,就告诉数据库:“我要修改这些数据,请把它们锁住。” 操作步骤是这样的:

- 开启一个事务。
- 执行带
FOR UPDATE的查询语句,你想锁住商品表中ID为1的商品信息,语句是:SELECT * FROM 商品表 WHERE id = 1 FOR UPDATE; - 这时,数据库就会给这条id=1的记录加上“排他锁”,这意味着:
- 在这个事务提交或回滚之前,其他任何事务都不能再用
SELECT ... FOR UPDATE或者SELECT ... LOCK IN SHARE MODE(另一种锁)来读取这条记录。 - 更重要的是,其他事务执行普通的
UPDATE、DELETE操作也会被卡住,一直等待你的锁释放。
- 在这个事务提交或回滚之前,其他任何事务都不能再用
- 你在当前事务里放心地进行你的业务操作,比如检查库存、计算新值。
- 执行更新操作:
UPDATE 商品表 SET 库存 = 新库存值 WHERE id = 1; - 提交事务:
COMMIT;,提交成功后,锁自动释放,其他在等待的事务才能继续操作这条数据。
第三步:了解另一种读锁——SELECT ... LOCK IN SHARE MODE 这是一种力度稍轻的悲观锁,叫“共享锁”,它的操作步骤和上面类似,但含义不同:
- 开启事务。
- 执行
SELECT * FROM 商品表 WHERE id = 1 LOCK IN SHARE MODE; - 这时,你给这条记录加的是“共享锁”,这意味着:
- 其他事务可以也使用
SELECT ... LOCK IN SHARE MODE来读取这条数据,大家共享这把锁。 - 任何事务(包括你自己)都不能修改这条数据,如果有事务尝试用
FOR UPDATE加排他锁或者直接UPDATE,也会被卡住等待。
- 其他事务可以也使用
- 这种锁适合用在“你只想确保在你读取后到修改前,数据绝对不被别人修改”的场景,但你自己可能不是立即修改,不过在实际中,
FOR UPDATE用得更多。
重要的注意事项和操作细节(根据常见数据库实践总结):
- 锁的释放时机:悲观锁的锁只有在事务结束(
COMMIT或ROLLBACK)时才会释放,如果你开了事务、加了锁,但长时间不提交,就会导致其他操作一直等待,可能拖垮系统,所以操作要快。 - 锁等待超时:如果一条记录被一个事务锁住了,另一个事务也想去锁它,默认会一直等,可以设置“等待超时”时间,比如在MySQL中设置
innodb_lock_wait_timeout参数,超过时间还等不到锁,数据库会报错,避免无限等待。 - 死锁问题:这是最需要注意的,比如事务A锁了记录1,想去锁记录2;同时事务B锁了记录2,想去锁记录1,两个人互相等,就“死锁”了,数据库会发现这种情况,并强制回滚其中一个事务,让它报错失败,你的程序需要能处理这种错误,通常就是捕获异常后重试一遍操作。
- 一定要用索引:你的
WHERE条件(比如上面的id = 1)必须用到索引列(比如主键id),如果你用WHERE 商品名 = 'xxx'而“商品名”这列没索引,数据库可能会锁住整张表,性能会急剧下降。 - 不同数据库的差异:
- Oracle:用法和MySQL的
FOR UPDATE非常相似。 - SQL Server:在查询时使用
WITH (UPDLOCK)这样的提示来实现类似效果,SELECT * FROM 商品表 WITH (UPDLOCK) WHERE id = 1。 - PostgreSQL:也支持
FOR UPDATE,行为大同小异。
- Oracle:用法和MySQL的
总结操作步骤全流程:
- 开启数据库事务(
BEGIN;)。 - 使用带
FOR UPDATE子句的SELECT语句,查询并锁定目标数据行(确保WHERE条件用索引)。 - 在程序中进行业务逻辑判断和计算。
- 执行UPDATE语句修改已被锁定的数据。
- 提交事务(
COMMIT;),释放锁,如果过程中发生错误,则回滚事务(ROLLBACK;),锁也会释放。
最后强调,悲观锁是一种强力但消耗性能的工具,它通过“先锁后改”保证了绝对的安全,但会让其他操作排队,在高并发场景下可能成为瓶颈,只有在冲突确实频繁发生、或者业务逻辑要求强一致性的关键环节(如扣减库存、支付余额)才考虑使用它,对于并发不高或者可以接受偶尔重试的场景,乐观锁(通过版本号控制)可能是更轻量、性能更好的选择。
本文由盘雅霜于2026-01-25发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://ismc.haoid.cn/wenda/85781.html
