Django 中事務的使用


在 Django 中可以通過django.db.transaction 模塊提供的atomic來定義一個事務

atomic提供兩種方案實現事務

  • 裝飾器用法:
from django.db import transaction

@transaction.atomic
def viewfunc(request):
  # 這些代碼會在一個事務中執行
  ......

裝飾器用法:整個視圖中所有 MySQL 數據庫的操作都看做一個事務,范圍太大,不夠靈活。而且無法直接作用於類視圖

  • with 語句用法:
from django.db import transaction

def viewfunc(request):
  # 這部分代碼不在事務中,會被 Django 自動提交
  ......

  with transaction.atomic():
      # 這部分代碼會在事務中執行
      ......

with 語句用法:可以靈活的有選擇性的把某些 MySQL 數據庫的操作看做一個事務。而且不用關心視圖的類型。

  • 三句話使用
from django.db import transaction

# 創建保存點
save_id = transaction.savepoint()

# 回滾到保存點
transaction.savepoint_rollback(save_id)

# 提交從保存點到當前狀態的所有數據庫事務操作
transaction.savepoint_commit(save_id)

使用事務保存訂單數據

class OrderCommitView(LoginRequiredJSONMixin, View):
    """訂單提交"""

    def post(self, request):
        """保存訂單信息和訂單商品信息"""
        # 獲取當前保存訂單時需要的信息
        ......

        # 顯式的開啟一個事務
        with transaction.atomic():
            # 創建事務保存點
            save_id = transaction.savepoint()

            # 暴力回滾
            try:
                # 保存訂單基本信息 OrderInfo(一)
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                # 從redis讀取購物車中被勾選的商品信息
                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                selected = redis_conn.smembers('selected_%s' % user.id)
                carts = {}
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])
                sku_ids = carts.keys()

                # 遍歷購物車中被勾選的商品信息
                for sku_id in sku_ids:
                    # 查詢SKU信息
                    sku = SKU.objects.get(id=sku_id)
                    # 判斷SKU庫存
                    sku_count = carts[sku.id]
                    if sku_count > sku.stock:
                        # 出錯就回滾
                        transaction.savepoint_rollback(save_id)
                        return http.JsonResponse({
                                  'code': RETCODE.STOCKERR, 
                                  'errmsg': '庫存不足'})

                    # SKU減少庫存,增加銷量
                    sku.stock -= sku_count
                    sku.sales += sku_count
                    sku.save()

                    # 修改SPU銷量
                    sku.goods.sales += sku_count
                    sku.goods.save()

                    # 保存訂單商品信息 OrderGoods(多)
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                    # 保存商品訂單中總價和總數量
                    order.total_count += sku_count
                    order.total_amount += (sku_count * sku.price)

                # 添加郵費和保存訂單信息
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({
                         'code': RETCODE.DBERR, 
                         'errmsg': '下單失敗'})

            # 提交訂單成功,顯式的提交一次事務
            transaction.savepoint_commit(save_id)

        # 清除購物車中已結算的商品
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id, *selected)
        pl.srem('selected_%s' % user.id, *selected)
        pl.execute()

        # 響應提交訂單結果
        return http.JsonResponse({'code': RETCODE.OK, 
                                  'errmsg': '下單成功', 
                                  'order_id': order.order_id})


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM