1. 程式人生 > >電商類微信小程式,庫存不超賣實現

電商類微信小程式,庫存不超賣實現

緣起

由於專案中需要實現一個買賣平臺的微信小程式,實現過程中,發現控制庫存不超賣是一個非常有意思的事情。

已獲知的情報

庫存超賣經常由於併發時有髒讀情況,通常實現庫存不超賣通過加鎖方式實現

1.樂觀鎖:假設不會發生併發衝突,只在提交操作時檢查是否違反資料完整性。樂觀鎖不能解決髒讀的問題。

2.悲觀鎖:指的是對資料被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,因此,在整個資料處理過程中,將資料處於鎖定狀態

鎖通常不能使用資料庫的鎖,應該使用快取,在有人操作之前加一個互斥變數,當這個變數沒有釋放,而另一個人申請訪問時,讀到快取中有這個互斥變數,應直接返回,我的專案中並沒有很大的併發量,所以直接使用了資料庫中的值

此外庫存減扣操作,如果在併發量比較大時,應該採用在快取中減扣,從而降低資料庫壓力

我選擇的方法

樂觀鎖+ update tb set col = col -num where col >= num

上程式碼

def reduce_inventory(*products):
    '''
    :desc:生成訂單之後做庫存減扣
    :return:減扣庫存狀態
    '''
    # 通過樂觀鎖 失敗就重試直至條件判出
    total_fee = 0.0
    reduce_status = False
    try:
        for product in products:
            product_id = int(product.get('product_id'))
            num = int(product.get('num'))
            price = 0.0
            while True:
                product_old = db.session.query(Product).filter_by(product_id=product_id).first()
                price = product_old.price
                if product_old:
                    update_time = product_old.update_time
                    update_time_str = datetime.datetime.strftime(update_time, '%Y-%m-%d %H:%M:%S')
                    product_inventor = product_old.product_inventor
                    if product_inventor is None:
                        reduce_status = True
                        break
                    elif product_inventor > 0:
                        if product_inventor < num:
                            reduce_status = False
                            break
                        sql = "update tb_product set product_inventor = product_inventor - " + str(int(num)) + \
                              " where product_inventor >= " + str(int(num)) + " and update_time = '" + update_time_str + \
                              "' and product_id = " + str(product_id) + ""
                        status = db.session.execute(sql)
                        print sql
                        row_count = status.rowcount
                        if not row_count:
                            reduce_status = False
                            continue
                        else:
                            reduce_status = True
                            break
                    elif product_inventor <= 0:
                        reduce_status = False
                        break
                else:
                    reduce_status = False
                    break
            if reduce_status:
                total_fee += float(price) * int(num)
            else:
                break
        if reduce_status:
            db.session.commit()
        else:
            db.session.rollback()
        return reduce_status, total_fee * 100
    except Exception as e:
        app.logger.exception('info')
        db.session.rollback()
        raise Exception(e)