分布式锁初探--数据库行锁

前言

关于抢红包服务一次数据库行锁控制并发,在此记录一下,或许里面还存在很多不足。

场景

抢红包应用:一个红包分为100个子红包,可以有N个人来抢这个红包,这时主要保证当有大于100个人来同时抢到这个红包,只能前100名抢到,并且所分配的红包金额不能大于发放红包金额。

1、发放红包

发红包过程比较简单,不涉及并发,这里简单说明。
这里写图片描述
以上为发放红包简单流程。
主代码生成主红记录,记录红包

insert into main_package(total_amount,remain_amout,total_num,remain_num)

2、抢红包流程

这里写图片描述
这里抢红包主要是控制并发,这里用了数据库行锁来控制伪代码如下:

int tryCount=0;
//加while循环,在发生并发时 失失败的情况可以重试,并且重试次数不大于10,避免数据库死锁,导致系统死循环
while(true && tryCount<10){
    tryCount ++;
    MainPackage mainPackage = select remain_amout,remain_num from main_package where orderid='orderid';
    //红包余额小于等于0,红包已被抢光,返回
    if(null == mainPacage || mainPackage.remainAmout<=0){
        return false;
    }
    //生成随机金额
    int randomAmount = getRandomAmount(mainPackage.remainAmout,mainPackage.remainNum);
    //防止随机金额生成错误
    if(randomAmount<=0){
        return false;
    }
    //更新主红包剩余金额及剩余个数,这里是利用 where条件里面加上红包余额来控制并发的
    int updateStatus = update main_package set remain_amout = mainPacage.remainAmout-randomAmount,
                              remain_num = remain_num-1 
                             where orderid='orderid' and remain_amout= mainPacage.remainAmout;
    if(updateStatus>0){
        //生成子红包,这里没有控制事物,子表手机号作为唯一索引防止并发重复抢红包。
        try{
        instert into sub_package(orderid,sub_orderid,amount,mobile  );
        }catch{
             //如果插入失败,将主表扣去的金额加回去
             try{
                  update main_package
            set REMAININGAMOUNT = REMAININGAMOUNT + #{redSubAmt}, REMAININGNUMBER = REMAININGNUMBER+1, where ORDERID = #{orderId}         
             }catch(){
                return;
             }
        }
        break;      
    }
}

我们做了并发测试,在qps可达到3000

猜你喜欢

转载自blog.csdn.net/lh87270202/article/details/79800927