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})

原文地址:https://www.cnblogs.com/oklizz/p/11240212.html

时间: 2024-07-30 14:19:52

Django 中事务的使用的相关文章

django中怎么使用mysql数据库的事务

Mysql数据库事务: 在进行后端业务开始操作修改数据库时,可能会涉及到多张表的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败. Django中对于数据库的事务,默认每执行一句数据库操作,便会自动提交.我们需要在保存数据库操作中自己控制数据库事务的执行流程. 在Django中可以通过django.db.transaction模块提供的atomic来定义一个事务,atomic提供两种用法: 装饰器用法 from django.db import transaction

Django中MySQL事务的使用

Django中事物的使用 from django.db import transaction @transaction.atomic通过transaction的@transaction.atomic装饰器来开启事务,在视图逻辑涉及数据库操作的地方添加事物保存点,在操作不满足时进行事物回滚,在操作满足是进行事物提交 # 前端传递的参数:地址id(addr_id) 支付方式(pay_method) 用户要购买的商品id字符串(sku_ids) # mysql事务: 一组sql操作,要么都成功,要么都

django中数据库事务的处理

今天在django中处理数据库数据时,用到事务,官方文档看不下去,网上查资料,那叫一个大海捞针啊,还找不到自己想要的效果. django中的事务, 依据Django1.6的文档,“Django提供了一种简单的API去控制数据库的事务交易...原子操作用来定义数据库事务的属性. 原子操作允许我们在数据库保证的前提下,创建一堆代码.如果这些代码被成功的执行,所对应的改变也会提交到数据库中.如果有异常发生,那么操作就会回滚.”可以采用装饰器用法或代码块用法,强力推荐代码块,如下. from djang

django中数据库事物的管理

事务(Transaction)是并发控制的基本单位.所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位.例如,银行转帐工作:从一个帐号扣款并使另一个帐号增款,这两个操作要么都执行,要么都不执行.所以,应该把他们看成一个事务.事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性. 在django1.8中事务的使用  注意:只要是已报异常,程序就自动回滚了.. from django.db import transaction #首先要导包 @

Django 数据库事务

管理数据库事务 Django框架提供了好几种方式来控制和管理数据库事务.(以下Django框架会简化为Django,读者可自行脑补框架两字) Django框架默认的事务行为 自动提交作为Django默认的事务行为,它表现形式为:每次数据库操作会立即被提交到数据库中,除非这个事务仍然处于激活状态. 那么,更多详细内容见下文. Django使用事务或者保存点来保证多个ORM操作的完整性,尤其是针对delete()和update()操作. 另外因为某些性能原因,Django提供的TestCase类就将

Django中的Json知识拾遗

  在做Django项目时,用到了很多AJax的知识,说到Ajax就会涉及到json的知识,因此索性准备来一篇博客,将项目过程中遇到的问题记录下,以方便日后的查阅. 一.什么是JSon? JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式. 它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据. 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言. 易于人阅读和编写,

在Django中使用原生Sql

在Django中使用原生Sql主要有以下几种方式: 一:extra:结果集修改器,一种提供额外查询参数的机制 二:raw:执行原始sql并返回模型实例 三:直接执行自定义Sql(这种方式完全不依赖model,前两种还是要依赖于model) 实例: 使用extra: 1:Book.objects.filter(publisher__name='广东人员出版社').extra(where=['price>50']) Book.objects.filter(publisher__name='广东人员出

django的事务

在某些时候,你可能会在视图修改两张数据表.并且想让他们同时成功或者同时失败.这就是事务的原子性(atomicity).在django中应该怎么做呢? 详细可以参考官方文档:https://yiyibooks.cn/xx/Django_1.11.6/topics/db/transactions.html 这里简单地记录一下: 1.装饰器方式实现 @transaction.atomic def viewfunc(request): # 这些代码会在一个事务中执行 ... 2.with语句方式实现 d

Django中涉及金融的项目

在Django中,如果一个项目涉及了金融,他的要求是十分严格的. 所以嘞,这里就有一些坑,很多坑,第一次开发的时候很容易出现一系列的错误 在涉及金融计算的地方,不能使用float类型 什么鬼,但事实就是如此,千万不要用float进行计算..... 所以,Python中为我们提供了一个专门的模块计算,decimal 而同样的,Django中也提供了相应的计算字段,DecimalField class DecimalField(max_digits=None, decimal_places=None