電商類微信小程式,庫存不超賣實現
阿新 • • 發佈:2019-02-05
緣起
由於專案中需要實現一個買賣平臺的微信小程式,實現過程中,發現控制庫存不超賣是一個非常有意思的事情。
已獲知的情報
庫存超賣經常由於併發時有髒讀情況,通常實現庫存不超賣通過加鎖方式實現
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)