7. 数据库锁和并发问题测试怎么讲?
数据库锁和并发问题,是区分普通功能测试和有质量意识测试的重要分水岭。很多业务在单用户操作时完全正常,一到多人同时操作就出问题,比如库存超卖、重复扣款、重复审批、优惠券重复使用、状态被覆盖。这类问题往往不是页面点点就能发现的,需要测试人员主动设计并发场景。
面试中问锁和并发,面试官通常不是想让你讲数据库锁的全部底层实现,而是想知道你有没有高风险业务意识:哪些场景容易并发出问题,怎么模拟并发,怎么判断数据是否异常,发现问题后怎么定位。测试工程师可以不深入到数据库内核,但必须能结合业务说清楚。
一、为什么会有并发问题
并发问题的本质是多个请求同时操作同一份或相关数据。如果系统没有做好锁、事务、幂等、状态校验,就可能出现数据错乱。
典型例子:商品库存只剩 1 件,两个用户同时提交订单。如果系统处理不当,两个订单都成功,库存变成 -1,这就是超卖。
再比如审批系统中,同一个单据同时被两个审批人点击通过,如果没有状态校验和并发控制,可能生成两条审批通过记录,或者后提交的人覆盖先提交的状态。
支付系统也常见:第三方支付回调可能重复通知,如果接口不幂等,就可能重复生成支付流水或重复发货。
二、测试中最常见的并发风险场景
1. 库存扣减
库存是并发测试最经典场景。关注点:库存不能为负、不能超卖、失败订单不能扣库存、取消订单是否释放库存。
2. 秒杀和抢购
大量用户抢少量商品,除了库存一致性,还要关注接口限流、排队、失败提示、响应时间。
3. 优惠券领取和使用
优惠券库存有限时,不能超发;同一张券不能被重复使用;支付失败后锁定券是否释放。
4. 支付回调
支付平台可能多次通知同一笔订单。系统必须保证重复回调不会重复改状态、重复发货、重复记账。
5. 审批流
多人同时审批同一节点,不能出现重复审批、状态回退、审批记录错乱。
6. 重复提交
用户连续点击提交按钮,或者前端重试,可能导致重复创建订单、重复提交工单、重复报名。
三、数据库锁怎么简单理解
测试面试不需要把锁讲成数据库课程,但要有基本概念。
行锁
锁住某一行数据,常用于更新库存、订单状态。比如更新某个商品库存时,只锁这条商品库存记录。
表锁
锁住整张表,粒度大,影响并发性能。一般业务系统应尽量避免不必要表锁。
悲观锁
假设并发冲突一定会发生,所以先加锁再操作。例如查询库存时加 for update,其他事务要等锁释放。
乐观锁
假设冲突不一定发生,更新时通过版本号或条件判断。例如库存扣减时加条件:
update t_stock
set stock = stock - 1
where product_id = 101
and stock > 0;
如果影响行数为 0,说明库存不足或被别人抢先扣了。
幂等控制
严格说幂等不等于锁,但并发测试中经常一起出现。比如同一个支付回调通知多次,系统应该只处理一次。
四、怎么设计并发测试
1. 明确并发对象
先明确多个请求是否操作同一资源。比如同一商品库存、同一订单、同一优惠券、同一审批单。
2. 明确预期结果
并发测试必须先定义正确结果。例如库存 1,同时 10 人下单,最多只能成功 1 单,其余应失败,库存不能小于 0。
3. 准备初始数据
并发前要查清楚初始库存、订单状态、优惠券状态。
4. 发起并发请求
可以用 JMeter、Postman Runner、脚本、自动化框架,也可以让开发提供压测接口。重点是尽量同时发起请求。
5. 校验数据库结果
并发请求结束后,不能只看响应成功数,还要查数据库:成功订单数、库存剩余、流水数量、状态记录。
五、完整案例:库存超卖测试
假设商品库存为 1,10 个用户同时购买。
测试前:
select product_id, stock
from t_product_stock
where product_id = 101;
预期:库存是 1。
并发请求:10 个用户同时调用创建订单接口。
测试后查询:
select count(*)
from t_order
where product_id = 101
and status in ('WAIT_PAY', 'PAID');
select product_id, stock
from t_product_stock
where product_id = 101;
正确结果:成功订单数最多 1,库存不能小于 0。
如果成功订单数大于 1,说明超卖;如果库存为 -1,也说明扣减逻辑有问题;如果所有请求都成功但库存没扣,说明库存校验缺失。
六、完整案例:支付回调重复通知
支付回调是实际项目高风险点。第三方支付平台可能因为网络原因重复通知同一笔支付结果。
测试步骤:
- 创建待支付订单;
- 模拟支付成功回调;
- 连续发送多次相同回调;
- 查询订单状态;
- 查询支付流水;
- 查询发货或权益发放记录。
预期:
- 订单只从待支付变成已支付一次;
- 成功支付流水只能有一条;
- 权益只能发放一次;
- 重复回调返回成功或已处理,但不能重复执行业务。
SQL 示例:
select order_no, status, pay_status
from t_order
where order_no = 'NO202604300001';
select count(*)
from t_pay_record
where order_no = 'NO202604300001'
and pay_status = 'SUCCESS';
七、常见定位思路
并发问题出现后,不要只说“系统有 Bug”。要能定位方向。
1. 看请求时间线
确认多个请求是否真的同时到达,还是顺序执行。
2. 看响应成功数
统计成功和失败数量,判断是否超过业务预期。
3. 查数据库最终状态
看库存、订单、流水、审批记录是否一致。
4. 看日志
关注是否有重复处理、事务回滚、唯一键冲突、锁等待、超时。
5. 分析是否缺少控制
可能缺少库存扣减条件、唯一约束、状态校验、幂等表、版本号或锁。
八、面试回答模板
如果面试官问“数据库锁和并发问题怎么测试”,可以这样答:
我会先从业务风险场景入手,比如库存扣减、优惠券领取、支付回调、审批流和重复提交。这些场景多个请求会同时操作同一份数据,容易出现超卖、重复扣款、重复审批或状态覆盖。测试时我会先准备明确的初始数据,比如库存为 1,然后用 JMeter 或脚本并发发起多个请求,最后不只看接口响应,还会查数据库里的成功订单数、库存剩余、支付流水和状态记录。对于定位,我会结合请求时间线、服务日志和数据库结果判断是否缺少锁、事务、幂等或状态校验。
九、常见追问
追问:怎么测超卖?
设置库存为 1,多个用户并发下单,预期最多 1 个成功,库存不能小于 0,失败订单不能扣库存。
追问:悲观锁和乐观锁怎么理解?
悲观锁是先锁住再操作,适合冲突高场景;乐观锁是更新时通过版本号或条件判断是否冲突,适合读多写少或冲突不高场景。
追问:重复支付怎么测?
对同一订单多次发起支付或重复发送支付回调,验证只能生成一条成功流水,订单状态不能重复变更,权益不能重复发放。
十、练习清单
- 设计库存为 1 的并发下单测试;
- 设计优惠券库存为 1 的并发领取测试;
- 设计同一订单重复支付测试;
- 设计支付回调重复通知测试;
- 设计审批单重复审批测试;
- 设计连续点击提交按钮测试;
- 用 SQL 验证库存不能为负;
- 用 SQL 验证成功流水唯一;
- 用 JMeter 模拟 10 个并发请求;
- 准备一段并发问题定位话术。
锁和并发测试的核心不是会说几个锁名,而是能识别高风险业务,设计并发场景,查数据库验证结果,并能定位可能缺少的控制机制。这才是面试官真正想听的。
配套刷题:

