Django 事物

目录

  Django 事物是什么

  Djnago 如何使用事务

Djnago 如何使用事务

1. 给一个Http请求绑定事务(全局事物)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day59',
        'USER': 'root',
        'PASSWORD': '123',
        "POST": '127.0.0.1',
        'PORT': 3306,
        'ATOMIC_REQUESTS': True, # 设置为True代表同一个http请求所对应的所有SQL放在一个事物中执行
                                # (要么同时成功,要么同时失败), 这是全局性的配置, 如果要对某个
                                # http请求放水(然后自定义事物), 可以用non_atomic_requests修饰器
        'OPTIONS': {
            "init_command": "SET storage_engine=INNODB",  # 设置创建表的存储引擎
        }
    }
}

 1.1 设置全局之后取消某个函数的事务,在视图函数添加装饰器@transaction.non_atomic_requests,则该视图不在事物之内。

from django.db import transaction
 
class xxx(xxxView):
    @transaction.non_atomic_requests
    def post(self, request, *args, **kwargs):
        pass

# 关闭其他除自己之外
@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

2.显式地控制事务(局部事物)

  原子性是数据库事务的一个属性。使用atomic,我们就可以创建一个具备原子性的代码块。一旦代码块正常运行完毕,

  所有的修改会被提交到数据库。反之,如果有异常,更改会被回滚。

  被atomic管理起来的代码块还可以内嵌到方法中。这样的话,即便内部代码块正常运行,如果外部代码块抛出异常的话,

  它也没有办法把它的修改提交到数据库中。

2.1 atomic 提供两种方案实现事务:

  2.1.1 atomic可以被当成装饰器使用

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

  实例:

  进入最外层atomic代码块时开启一个事务;

  进入内部atomic代码块时创建保存点;

  退出内部atomic时释放或回滚事务;

  退出最外层atomic代码块时提交或者回滚事务;

"""创建订单"""
class Creat(APIView):
    @transaction.atomic
    def post(self,request):
        param=request.data
        form_obj=OrderForm(param)

        if form_obj.is_valid() and param['buy_list']:
            if request.META.get("HTTP_X_FORWARDED_FOR"):
                host_ip = request.META["HTTP_X_FROWARDED_FOR"]
            else:
                host_ip = request.META["REMOTE_ADDR"]
            user_cache=cache.get(param['token'])
            if user_cache:
                openid=user_cache.split("&")[0]
                user_data=models.WxUser.objects.filter(openid=openid).first()
                order_data = {"consignee_mobile": param['phone'],
                            'consignee_name': param['name'],
                            'wxuser_id': user_data.id,
                            "memo": param['remark'],
                            "consignee_area":f"{param['province']},{param['city']},{param['county']}",
                            "consignee_address":param['address'] ,
                            }
                buy_list=param['buy_list']
                goods_key=list(buy_list.keys())
                all_product=models.Product.objects.filter(product_id__in=goods_key)
                order_data['order_id']=func.get_order_id()
                order_data['order_total']=0
                order_data['quantity']=0
                #开启库存
                sid=transaction.savepoint()
                for product in all_product:
                    product.product_id=str(product.product_id)
                    order_data['order_total']+=product.price*buy_list[product.product_id]
                    order_data['quantity']+=buy_list[product.product_id]
                    #创建子订单
                    for i in range(3):
                        #查询当前库存
                        stock=product.stock.quantity
                        #当前减轻购买的数量,等于剩余的库存
                        new_stock=stock-buy_list[product.product_id]
                        #判断库存是否足够
                        if new_stock<0:
                            #回滚
                            transaction.savepoint_rollback(sid)
                            #如果库存不住够,我们直接返回
                            return Response({"code":203,"msg":f"{product.name}库存不足"})
                        res=models.Stock.objects.filter(quantity=stock,stock_id=product.stock.stock_id).update(quantity=new_stock)
                        if not  res:
                            if i==2:
                                transaction.savepoint_rollback(sid)
                                return Response({"code": 203, "msg": f"创建订单失败"})
                            else:
                                continue
                        else:
                            break
                    new_buy_count = product.buy_count + buy_list[product.product_id]
                    models.Product.objects.filter(product_id=product.product_id).update(buy_count=new_buy_count)
                    order_item_data={'order_id': order_data['order_id'], 'product_id': product.product_id,
                                "name": product.name, "image": product.image, "price": product.price,
                                "nums": buy_list[product.product_id], "brief": product.brief}
                    models.Order_items.objects.create(**order_item_data)
                models.Order.objects.create(**order_data)
                pay_methon="Wxpay"
                try:
                    pay_file=importlib.import_module(f"app01.Pay.{pay_methon}")
                    pay_class=getattr(pay_file,pay_methon)
                    order_data['open_id'] = openid
                    order_data['ip']=host_ip
                    data=pay_class().pay(order_data)
                except:
                    transaction.savepoint_rollback(sid)
                    return Response({"code": 200, "msg": "未知的支付方式" })

                transaction.savepoint_commit(sid)
                func.add_task(order_data['order_id'])
                return Response({"code": 200, "msg": "ok" ,"data":data})

            else:
                return Response({"code":202,"msg":"token已过期"})
        else:
            return Response({"code":201,"msg":"缺少参数"})

2.1.2 下面是被当做上下文管理器来使用

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()
    with transaction.atomic():
        # This code executes inside a transaction.
        do_more_stuff()

  实例:

from django.db import transaction
  with transaction.atomic():
        # 这部分代码会在事务中执行
        # 创建保存点
        save_id = transaction.savepoint()
        try:
            ....
        except:
             # 回滚到保存点
             transaction.savepoint_rollback(save_id)
        # 提交从保存点到当前状态的所有数据库事务操作
        transaction.savepoint_commit(save_id)

 

posted @ 2020-03-25 17:34  zhuang6  阅读(225)  评论(0)    收藏  举报