def createOrder(self, member_id, items=None, params=None): resp = {'code': 200, 'msg': '操作成功~', 'data': {}} pay_price = decimal.Decimal(0.00) continue_cnt = 0 food_ids = [] for item in items: if decimal.Decimal(item['price']) < 0: continue_cnt += 1 continue pay_price = pay_price + decimal.Decimal(item['price']) * int( item['number']) food_ids.append(item['id']) if continue_cnt >= len(items): resp['code'] = -1 resp['msg'] = '商品items为空~~' return resp yun_price = params[ 'yun_price'] if params and 'yun_price' in params else 0 note = params['note'] if params and 'note' in params else '' express_address_id = params[ 'express_address_id'] if params and 'express_address_id' in params else 0 express_info = params[ 'express_info'] if params and 'express_info' in params else {} yun_price = decimal.Decimal(yun_price) total_price = pay_price + yun_price try: # 为了防止并发库存出问题了,使用行锁select for update(悲观锁 ) tmp_food_list = db.session.query( Food ).filter( Food.id.in_( food_ids ) )\ .with_for_update().all() tmp_food_stock_mapping = {} for tmp_item in tmp_food_list: tmp_food_stock_mapping[tmp_item.id] = tmp_item.stock model_pay_order = PayOrder() model_pay_order.order_sn = self.geneOrderSn() model_pay_order.member_id = member_id model_pay_order.total_price = total_price model_pay_order.yun_price = yun_price model_pay_order.pay_price = pay_price model_pay_order.note = note model_pay_order.status = -8 model_pay_order.express_status = -8 model_pay_order.express_address_id = express_address_id model_pay_order.express_info = json.dumps(express_info) model_pay_order.updated_time = model_pay_order.created_time = getCurrentDate( ) db.session.add(model_pay_order) db.session.flush() for item in items: tmp_left_stock = tmp_food_stock_mapping[item['id']] if decimal.Decimal(item['price']) < 0: continue if int(item['number']) > int(tmp_left_stock): raise Exception("您购买的这美食太火爆了,剩余:%s,你购买%s~~" % (tmp_left_stock, item['number'])) tmp_ret = Food.query.filter_by(id=item['id']).update( {"stock": int(tmp_left_stock) - int(item['number'])}) if not tmp_ret: raise Exception("下单失败请重新下单") tmp_pay_item = PayOrderItem() tmp_pay_item.pay_order_id = model_pay_order.id tmp_pay_item.member_id = member_id tmp_pay_item.quantity = item['number'] tmp_pay_item.price = item['price'] tmp_pay_item.food_id = item['id'] tmp_pay_item.note = note tmp_pay_item.updated_time = tmp_pay_item.created_time = getCurrentDate( ) db.session.add(tmp_pay_item) #db.session.flush() FoodService.setStockChangeLog(item['id'], -item['number'], "在线购买") db.session.commit() resp['data'] = { 'id': model_pay_order.id, 'order_sn': model_pay_order.order_sn, 'total_price': str(total_price) } except Exception as e: db.session.rollback() print(e) resp['code'] = -1 resp['msg'] = "下单失败请重新下单" resp['msg'] = str(e) return resp return resp
def createOrder(self, Cid, Shopid, items=None, params=None, recharge=None): resp = {'code': 200, 'msg': "操作成功", 'data': {}} pay_price = decimal.Decimal(0.00) continue_count = 0 product_id = [] for item in items: if decimal.Decimal(item['price']) < 0: continue_count += 1 continue pay_price = pay_price + decimal.Decimal(item['price']) * int( item['number']) if recharge != 'recharge': product_id.append(item['Pid']) if continue_count >= len(items): resp['code'] = -1 resp['msg'] = "商品为空" return resp yun_price = params['yun_price'] if 'yun_price' in params else 0 # note = params['note'] if 'note' in params else 0 express_address_id = params[ 'express_address_id'] if params and 'express_address_id' in params else 0 express_info = params[ 'express_info'] if params and 'express_info' in params else {} yun_price = decimal.Decimal(yun_price) total_price = yun_price + pay_price # 并发处理 try: # 开启事务 tmp_product_list = db.session.query(Product).filter( Product.Pid.in_(product_id)).with_for_update().all() tmp_product_stock_mapping = {} for tmp_item in tmp_product_list: tmp_product_stock_mapping[tmp_item.Pid] = tmp_item.ProductStock #支付订单 model_pay_order = PayOrder() model_pay_order.member_id = Cid model_pay_order.Shopid = Shopid model_pay_order.order_sn = self.geneOrderSn() model_pay_order.total_price = total_price model_pay_order.yun_price = yun_price model_pay_order.pay_price = pay_price # model_pay_order.note = note if recharge != 'recharge': model_pay_order.status = -8 model_pay_order.express_status = -8 else: model_pay_order.status = 11 model_pay_order.express_status = 11 model_pay_order.express_address_id = express_address_id model_pay_order.express_info = json.dumps(express_info) model_pay_order.updated_time = model_pay_order.created_time = getCurrentDate( ) db.session.add(model_pay_order) for item in items: if recharge != 'recharge': tmp_left_stock = tmp_product_stock_mapping[item['Pid']] if decimal.Decimal(item['price']) < 0: continue if int(item['number']) > int(tmp_left_stock): raise Exception("该商品剩余: %s" % (tmp_left_stock)) result = int(tmp_left_stock) - int(item['number']) tmp_ret = Product.query.filter_by(Pid=item['Pid']).update( {'ProductStock': int(result)}) if not tmp_ret: raise Exception("下单失败") tmp_pay_item = PayOrderItem() tmp_pay_item.pay_order_id = model_pay_order.id tmp_pay_item.member_id = Cid tmp_pay_item.quantity = item['number'] tmp_pay_item.price = item['price'] tmp_pay_item.Pid = item['Pid'] # tmp_pay_item.note = note tmp_pay_item.updated_time = tmp_pay_item.created_time = getCurrentDate( ) if recharge != 'recharge': ProductService.setStockChangeLog(item['Pid'], result) db.session.add(tmp_pay_item) # 提交事务 db.session.commit() resp['data'] = { 'id': model_pay_order.id, 'order_sn': model_pay_order.order_sn, 'total_price': str(model_pay_order.total_price) } except Exception as e: db.session.rollback() print(e) resp['code'] = -1 resp['msg'] = "下单失败请重新下单" resp['msg'] = str(e) return resp
def createOrder(self, member_id, items=None, params=None): # 创建订单(哪个用户,商品列表,params额外字段[留言] ) """ 实现下单并发,库存减少 :param member_id: :param items: :param params: :return: """ resp = {'code': 200, 'msg': '操作成功~', 'data': {}} pay_price = decimal.Decimal(0.00) # 商品总价格 continue_cnt = 0 food_ids = [] for item in items: # 遍历所有下单的商品 if decimal.Decimal(item['price']) < 0: # 如果有的商品价格<0。那么统计次数,并且跳过 continue_cnt += 1 continue pay_price = pay_price + decimal.Decimal(item['price']) * int( item['number']) # 此时的,商品总价格。就是,初始价格0.00 + 上面跳过的商品价格 * 下单数量 food_ids.append(item['id']) # 在这里面添加,通过的商品的 id if continue_cnt >= len(items): # 如果跳过的次数 >= 下单商品的数量。说明没有选择商品 resp['code'] = -1 resp['msg'] = '商品items为空~~' return resp yun_price = params[ 'yun_price'] if params and 'yun_price' in params else 0 note = params['note'] if params and 'note' in params else '' express_address_id = params[ 'express_address_id'] if params and 'express_address_id' in params else 0 express_info = params[ 'express_info'] if params and 'express_info' in params else {} yun_price = decimal.Decimal(yun_price) total_price = pay_price + yun_price # 并发处理 乐观锁和悲观锁。这里采用的是观锁。(悲观锁:锁数据表行记录。乐观锁:数据表增加一个字段,每次更新时对它进行判断 ) try: # 为了防止并发库存出问题了,我们坐下selectfor update, 这里可以给大家演示下 tmp_food_list = db.session.query(Food).filter(Food.id.in_(food_ids)) \ .with_for_update().all() # 锁定所有本次下单的商品id,行记录 tmp_food_stock_mapping = {} # 临时的商品库存 map,方便对比 for tmp_item in tmp_food_list: tmp_food_stock_mapping[ tmp_item.id] = tmp_item.stock # 被锁定的商品 库存 model_pay_order = PayOrder() model_pay_order.order_sn = self.geneOrderSn() # 随机订单号,通过随机算法算出 model_pay_order.member_id = member_id model_pay_order.total_price = total_price model_pay_order.yun_price = yun_price model_pay_order.pay_price = pay_price model_pay_order.note = note # 备注信息 model_pay_order.status = -8 # 默认状态:-8待付款 model_pay_order.express_status = -8 # 待支付 model_pay_order.express_address_id = express_address_id model_pay_order.express_info = json.dumps(express_info) model_pay_order.updated_time = model_pay_order.created_time = getCurrentData( ) db.session.add(model_pay_order) db.session.flush() for item in items: # 第一次判断,剩下的商品(跳出的商品) tmp_left_stock = tmp_food_stock_mapping[item['id']] if decimal.Decimal(item['price']) < 0: # 如果是价格<=0,就停止本次操作,继续 continue if int(item['number']) > int(tmp_left_stock): # 如果下单的商品数量 > 库存 raise Exception("您购买的这美食太火爆了,剩余:%s,您购买%s~~" % (tmp_left_stock, item['number'])) tmp_ret = Food.query.filter_by(id=item['id']).update( {"stock": int(tmp_left_stock) - int(item['number'])}) # 更新库存 if not tmp_ret: raise Exception("下单失败请重新下单") tmp_pay_item = PayOrderItem() # 生成订单 tmp_pay_item.pay_order_id = model_pay_order.id tmp_pay_item.member_id = member_id tmp_pay_item.quantity = item['number'] # 下单数量 tmp_pay_item.price = item['price'] # 商品单价 tmp_pay_item.food_id = item['id'] # 商品id tmp_pay_item.note = note # 备注信息 tmp_pay_item.updated_time = tmp_pay_item.created_time = getCurrentData( ) db.session.add(tmp_pay_item) db.session.flush() FoodService.setStockChangeLog(item['id'], -item['number'], "在线购买") # 商品变更记录。商品id,-数量,备注 db.session.commit() # 直到完成本次提交,行锁才解开 resp['data'] = { # 下单成功,返回数据 'id': model_pay_order.id, 'order_sn': model_pay_order.order_sn, 'total_price': str(total_price) } except Exception as e: pass db.session.rollback() # 如果出现异常,数据回滚,回到操作前的状态 print("*" * 50, e) resp['code'] = -1 resp['msg'] = "下单失败请重新下单" resp['msg'] = str(e) return resp return resp
def createOrder(self, member_id, items=None, params=None, eat_method=''): resp = {'code': 200, 'msg': '操作成功', 'data': {}} pay_price = decimal.Decimal(0.00) continue_cnt = 0 food_ids = [] for item in items: if decimal.Decimal(item['price']) < 0: continue_cnt += 1 continue pay_price = pay_price + \ (decimal.Decimal(item['price']) * int(item['number'])) food_ids.append(item['id']) if continue_cnt >= len(items): # 下单数量超过 选中数量,不成立 resp['code'] = -1 resp['msg'] = "商品items为空" return resp yun_price = params[ 'yun_price'] if params and 'yun_price' in params else 0 note = params['note'] if params and 'note' in params else '' express_address_id = params[ 'express_address_id'] if params and 'express_address_id' in params else 0 express_info = params[ 'express_info'] if params and 'express_info' in params else {} yun_price = decimal.Decimal(yun_price) total_price = pay_price + yun_price # 并发处理,加入库存 # 悲观锁 或者 乐观锁 try: # db.session.query( Food ).filter( Food.id.in_( food_ids ) )\ tmp_food_list = db.session.query(Food).filter(Food.id.in_(food_ids))\ .with_for_update().all() # 进行悲观锁 操作 # z只有rollback或者commit都能解锁; # time.sleep( 10 ) # 下单表 和 下单从表--加入数据 tmp_food_stock_mapping = {} for tmp_item in tmp_food_list: # 注意对象不能用数组来做,只能用属性值! tmp_food_stock_mapping[tmp_item.id] = tmp_item.stock model_pay_order = PayOrder() model_pay_order.order_sn = self.geneOrderSn() # 产生的 随机订单号 model_pay_order.member_id = member_id model_pay_order.total_price = total_price model_pay_order.pay_price = pay_price model_pay_order.yun_price = yun_price model_pay_order.note = note model_pay_order.status = -8 model_pay_order.express_status = -8 model_pay_order.express_address_id = express_address_id model_pay_order.express_info = json.dumps(express_info) model_pay_order.prepay_id = eat_method # 修改eat model_pay_order.updated_time = getCurrentDate() db.session.add(model_pay_order) # 从表添加 for item in items: tmp_left_stock = tmp_food_stock_mapping[item['id']] # 异常判断/处理 if decimal.Decimal(item['price']) < 0: continue if int(item['number']) > int(tmp_left_stock): # 直接抛出异常 raise Exception("您购买的美食太火爆了,剩余:%s,您购买:%s" % (tmp_left_stock, item['number'])) # 数据库处理 tmp_ret = Food.query.filter_by(id=item['id']).update( {"stock": int(tmp_left_stock) - int(item['number'])}) if not tmp_ret: raise Exception("下单失败请重新下单") tmp_pay_item = PayOrderItem() tmp_pay_item.pay_order_id = model_pay_order.id tmp_pay_item.member_id = member_id tmp_pay_item.quantity = item['number'] tmp_pay_item.price = item['price'] tmp_pay_item.food_id = item['id'] tmp_pay_item.note = note tmp_pay_item.updated_time = tmp_pay_item.created_time = getCurrentDate( ) db.session.add(tmp_pay_item) # 库存处理,减少库存 FoodService.setStockChangeLog(item['id'], -item['number'], "在线购买") db.session.commit() # 下单成功,返回相应数据 resp['data'] = { 'id': model_pay_order.id, 'order_sn': model_pay_order.order_sn, 'total_price': str(total_price), } except Exception as e: # 如果抛出错误,进行回滚 db.session.rollback() print(e) resp['code'] = -1 resp['msg'] = "下单失败请重新下单" resp['msg'] = str(e) return resp return resp