今天爱分享给大家带来乐观锁、悲观锁、数据库行锁 RPC调用的幂【面试题详解】,希望能够帮助到大家。
先说结论:建议优先用数据库行锁的做法更新额度。mysql数据库的tps我了解到的一个值是4000,大部分场景是满足的。各应用的真实情况还需要自行再压测。不建议刚开始就引入redis等中间件增加复杂度。
以下主要讨论:乐观锁、悲观锁、数据库行锁。RPC调用的幂等问题
数据库行锁(建议):通过where 条件限制不会超额或者超卖
// 其中seq=#{seq}的seq指额表记录的业务主键:在根据个人限额的场景下可能是身份证信息或者卡号;在根据产品限额的场景下可能就是产品码
String sql="update limit_info set avai_amount= avai_amount - #{current}
where seq=#{seq} and avai_amount > #{current}";
int res = excute(sql);
//根据影响的行数,res是0还是1判断更新是否成功
以下列举下悲观锁及乐观锁的写法以及可能存在的问题
悲观锁:select…for update。缺点:性能会有所下降,大部分业务场景不需要悲观锁。
//开启事务
begin();
Bigdecimal avaiAmount = excute("select avai_amount from limit where id=#{id} for update");
Bigdecimal newAvaiAmount = avaiAmount - current;
//判断余额是否足够
//更新余额
if(newAvaiAmount.compareTo(BigDecimal.ZERO) >= 0){
int res = excute("update limit_info set avai_amount=#{newAvaiAmount} where id=#{id}");
}
commit();
乐观锁:update时添加条件avai_amount=#{avaiAmount}。缺点:要有重试机制,增加了代码复杂度。
Bigdecimal avaiAmount = excute("select avai_amount from limit_info where id=#{id}");
Bigdecimal newAvaiAmount = avaiAmount - current;
//判断余额是否足够
//更新余额
if(newAvaiAmount.compareTo(BigDecimal.ZERO) >= 0){
int res = excute("update limit_info set avai_amount=#{newAvaiAmount}
where id=#{id} and avai_amount=#{avaiAmount}");
}
ps: 互金理财应用里关于按天控制额度用sql的写法(基金生产在用的做了简化):
--冻结客户交易份额 update LIMIT_INFO set USED_AMT = CASE WHEN WORK_DATE = #workDate# then USED_AMT + #usedAmt# else #usedAmt# end, WORK_DATE = #wokdDate#, MAX_AMT = #maxAmt#, where CST_NO = #cstNo# AND CASE WHEN WORK_DATE = #workDate# then USED_AMT + #usedAmt# else #usedAmt# end <= MAX_AMT --回滚已使用额度 update LIMIT_INFO SET USED_AMT = CASE WHEN WORK_DATE = #workDate# then USED_AMT - #usedAmt# else 0 end, WORK_DATE = #workDate#, WHERE CST_NO = #cstNo# AND WORK_DATE <= #workDate# AND (CASE WHEN WORK_DATE = #workDate# then USED_AMT - #usedAmt# else 0 end) >= 0
原文链接:https://blog.itblood.com/3998.html,转载请注明出处。

![办公室Private AI版[PC+安卓/5.37G/更新]The Office [Private Tutoring] [欧美SLG/汉化/动态]](/wp-content/uploads/replace/2025/10/25/265f1ee7ae5665ac600697f373680470.webp)