django订单部分--数据库事务

订单数据库设计

订单号不再采用数据库自增主键,而是由后端生成创建。

终端命令python manage.py startapp orders 创建订单应用orders,编辑模型类models.py

from django.db import models
from meiduo_mall.utils.models import BaseModel
from users.models import User, Address
from goods.models import SKU

# Create your models here.

class OrderInfo(BaseModel):
    """
    订单信息
    """
    PAY_METHODS_ENUM = {
        "CASH": 1,
        "ALIPAY": 2
    }

    PAY_METHOD_CHOICES = (
        (1, "货到付款"),
        (2, "支付宝"),
    )

    ORDER_STATUS_ENUM = {
        "UNPAID": 1,
        "UNSEND": 2,
        "UNRECEIVED": 3,
        "UNCOMMENT": 4,
        "FINISHED": 5
    }

    ORDER_STATUS_CHOICES = (
        (1, "待支付"),
        (2, "待发货"),
        (3, "待收货"),
        (4, "待评价"),
        (5, "已完成"),
        (6, "已取消"),
    )

    order_id = models.CharField(max_length=64, primary_key=True, verbose_name="订单号")
    user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="下单用户")
    address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="收获地址")
    total_count = models.IntegerField(default=1, verbose_name="商品总数")
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")
    freight = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="运费")
    pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式")
    status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")

    class Meta:
        db_table = "tb_order_info"
        verbose_name = ‘订单基本信息‘
        verbose_name_plural = verbose_name

class OrderGoods(BaseModel):
    """
    订单商品
    """
    SCORE_CHOICES = (
        (0, ‘0分‘),
        (1, ‘20分‘),
        (2, ‘40分‘),
        (3, ‘60分‘),
        (4, ‘80分‘),
        (5, ‘100分‘),
    )
    order = models.ForeignKey(OrderInfo, related_name=‘skus‘, on_delete=models.CASCADE, verbose_name="订单")
    sku = models.ForeignKey(SKU, on_delete=models.PROTECT, verbose_name="订单商品")
    count = models.IntegerField(default=1, verbose_name="数量")
    # max_digits :最大的位数。decimal_places :小数点后面保留多少位
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="单价")
    comment = models.TextField(default="", verbose_name="评价信息")
    score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5, verbose_name=‘满意度评分‘)
    is_anonymous = models.BooleanField(default=False, verbose_name=‘是否匿名评价‘)
    is_commented = models.BooleanField(default=False, verbose_name=‘是否评价了‘)

    class Meta:
        db_table = "tb_order_goods"
        verbose_name = ‘订单商品‘
        verbose_name_plural = verbose_name

settings.py配置文件(红色斜体):

INSTALLED_APPS = [
    ‘django.contrib.admin‘,
    ‘django.contrib.auth‘,
    ‘django.contrib.contenttypes‘,
    ‘django.contrib.sessions‘,
    ‘django.contrib.messages‘,
    ‘django.contrib.staticfiles‘,

    ‘rest_framework‘,
    ‘corsheaders‘,
    ‘ckeditor‘,  # 富文本编辑器
    ‘ckeditor_uploader‘,  # 富文本编辑器上传图片模块
    ‘django_crontab‘,  # 定时任务
    ‘haystack‘,#对接Elasticsearch

    ‘users.apps.UsersConfig‘,#注册用户模块应用
    ‘verifications.apps.VerificationsConfig‘,#验证模块
    ‘oauth.apps.OauthConfig‘,#第三方登录
    ‘areas.apps.AreasConfig‘,#省市区数据
    ‘contents.apps.ContentsConfig‘,#主页广告内容
    ‘goods.apps.GoodsConfig‘,#商品信息
    ‘orders.apps.OrdersConfig‘, # 订单

]

生成迁移文件并执行迁移:

python manage.py makemigrations

python manage.py migrate

订单结算

订单结算页面所需的数据从购物车中勾选而来。

在orders/serialziers.py中创建序列化器

class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label=‘数量‘)

    class Meta:
        model = SKU
        fields = (‘id‘, ‘name‘, ‘default_image_url‘, ‘price‘, ‘count‘)

class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label=‘运费‘, max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)

在orders/views.py中编写视图:

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from django_redis import get_redis_connection
from rest_framework.response import Response
from decimal import Decimal

from goods.models import SKU
from . import serializers

class OrderSettlementView(APIView):
    """
    订单结算
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """
        获取
        """
        user = request.user

        # 从购物车中获取用户勾选要结算的商品信息
        redis_conn = get_redis_connection(‘carts‘)
        # 存放的是redis中所有的购物车数据(包含了勾选的和未勾选的)
        redis_cart = redis_conn.hgetall(‘cart_%s‘ % user.id)
        # 读取出购物车中被勾选的商品的sku_id
        cart_selected = redis_conn.smembers(‘selected_%s‘ % user.id)

        cart = {} # 保存被勾选的商品的信息
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 查询商品信息
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku.count = cart[sku.id]

        # 运费
        # float 1.23  ==>  123 * 10 ^ -2  ==> 1.2299999999...
        # Decimal 1.23   1(整数部分)  23(小数部分)   ==> 1.23
        freight = Decimal(‘10.00‘)

        serializer = serializers.OrderSettlementSerializer({‘freight‘: freight, ‘skus‘: skus})
        return Response(serializer.data)

配置主路由(红色加粗斜体):

urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    #验证码
    url(r‘^‘,include(‘verifications.urls‘)),
    #用户
    url(r‘^‘,include(‘users.urls‘)),
    #QQ登录
    url(r‘^oauth/‘,include(‘oauth.urls‘)),
    # 省市区
    url(r‘^‘, include(‘areas.urls‘)),
    # CKEditor
    url(r‘^ckeditor/‘, include(‘ckeditor_uploader.urls‘)),
    # 商品
    url(r‘^‘, include(‘goods.urls‘)),
    # 购物车
    url(r‘^‘, include(‘carts.urls‘)),
    # 订单
    url(r‘^‘, include(‘orders.urls‘)),

]

orders/urls.py中添加路由:

from django.conf.urls import url
from . import views

urlpatterns = [
    # 确认订单
    url(r‘^orders/settlement/$‘, views.OrderSettlementView.as_view()),
]

前端:修改place_order.html,增加Vue变量,新建place_order.js

保存订单

在orders/views.py中创建视图:

class CommitOrderView(CreateAPIView):
    """提交订单"""

    # 登录用户才能访问
    permission_classes = [IsAuthenticated]
    # 指定序列化器
    serializer_class = serializers.CommitOrderSerializer

在orders/serializers.py中创建序列化器:

class CommitOrderSerializer(serializers.ModelSerializer):
    """提交订单"""

    class Meta:
        model = OrderInfo
        # order_id :输出;address 和 pay_method : 输入
        fields = (‘order_id‘, ‘address‘, ‘pay_method‘)
        read_only_fields = (‘order_id‘,)
        # 指定address 和 pay_method 为输出
        extra_kwargs = {
            ‘address‘: {
                ‘write_only‘: True,
            },
            ‘pay_method‘: {
                ‘write_only‘: True,
            }
        }

    def create(self, validated_data):
        """保存订单"""
        pass
        

保存订单的思路

def create(self, validated_data):
    # 获取当前下单用户

    # 生成订单编号

    # 保存订单基本信息数据 OrderInfo

    # 从redis中获取购物车结算商品数据

    # 遍历结算商品:

        # 判断商品库存是否充足

        # 减少商品库存,增加商品销量

        # 保存订单商品数据

    # 在redis购物车中删除已计算商品数据

数据库事务

在保存订单数据中,涉及到多张表(OrderInfo、OrderGoods、SKU)的数据修改,对这些数据的修改应该是一个整体事务,即要么一起成功,要么一起失败。

Django中对于数据库的事务,默认每执行一句数据库操作,便会自动提交。我们需要在保存订单中自己控制数据库事务的执行流程。

在Django中可以通过django.db.transaction模块提供的atomic来定义一个事务,atomic提供两种用法

装饰器用法:可以装饰在视图函数上

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # 这些代码会在一个事务中执行
    ...

with语句用法

from django.db import transaction

def viewfunc(request):
    # 这部分代码不在事务中,会被Django自动提交
    ...

    with transaction.atomic():
        # 这部分代码会在事务中执行
        ...

在Django中,还提供了保存点的支持,可以在事务中创建保存点来记录数据的特定状态,数据库出现错误时,可以恢复到数据保存点的状态

from django.db import transaction

# 创建保存点
save_id = transaction.savepoint()  

# 回滚到保存点
transaction.savepoint_rollback(save_id)

# 提交从保存点到当前状态的所有数据库事务操作
transaction.savepoint_commit(save_id)

保存订单数据create方法实现

   def create(self, validated_data):
        """
        保存订单
        """
        # 获取当前下单用户
        user = self.context[‘request‘].user

        # 组织订单编号 20170903153611+user.id
        # timezone.now() -> datetime
        order_id = timezone.now().strftime(‘%Y%m%d%H%M%S‘) + (‘%09d‘ % user.id)

        address = validated_data[‘address‘]
        pay_method = validated_data[‘pay_method‘]

        # 生成订单
        with transaction.atomic():
            # 创建一个保存点
            save_id = transaction.savepoint()

            try:
                 # 创建订单信息
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal(0),
                    freight=Decimal(10),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM[‘UNSEND‘] if pay_method == OrderInfo.PAY_METHODS_ENUM[‘CASH‘] else OrderInfo.ORDER_STATUS_ENUM[‘UNPAID‘]
                )
                # 获取购物车信息
                redis_conn = get_redis_connection("cart")
                redis_cart = redis_conn.hgetall("cart_%s" % user.id)
                cart_selected = redis_conn.smembers(‘cart_selected_%s‘ % user.id)

                # 将bytes类型转换为int类型
                cart = {}
                for sku_id in cart_selected:
                    cart[int(sku_id)] = int(redis_cart[sku_id])

                # 一次查询出所有商品数据
                skus = SKU.objects.filter(id__in=cart.keys())

                # 处理订单商品
                for sku in skus:
                    sku_count = cart[sku.id]

                    # 判断库存
                    origin_stock = sku.stock  # 原始库存
                    origin_sales = sku.sales  # 原始销量

                    if sku_count > origin_stock:
                        transaction.savepoint_rollback(save_id)
                        raise serializers.ValidationError(‘商品库存不足‘)

                    # 用于演示并发下单
                    # import time
                    # time.sleep(5)

                    # 减少库存
                    new_stock = origin_stock - sku_count
                    new_sales = origin_sales + sku_count

                    sku.stock = new_stock
                    sku.sales = new_sales
                    sku.save()

                    # 累计商品的SPU 销量信息
                    sku.goods.sales += sku_count
                    sku.goods.save()

                    # 累计订单基本信息的数据
                    order.total_count += sku_count  # 累计总金额
                    order.total_amount += (sku.price * sku_count)  # 累计总额

                    # 保存订单商品
                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=sku_count,
                        price=sku.price,
                    )

                # 更新订单的金额数量信息
                order.total_amount += order.freight
                order.save()

            except ValidationError:
                raise
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                raise

            # 提交事务
            transaction.savepoint_commit(save_id)

            # 更新redis中保存的购物车数据
            pl = redis_conn.pipeline()
            pl.hdel(‘cart_%s‘ % user.id, *cart_selected)
            pl.srem(‘cart_selected_%s‘ % user.id, *cart_selected)
            pl.execute()
            return order

并发处理

在多个用户同时发起对同一个商品的下单请求时,先查询商品库存,再修改商品库存,会出现资源竞争问题,导致库存的最终结果出现异常。

解决办法:

悲观锁

  • 当查询某条记录时,即让数据库为该记录加锁,锁住记录后别人无法操作,使用类似如下语法
select stock from tb_sku where id=1 for update;

SKU.objects.select_for_update().get(id=1)

悲观锁类似于我们在多线程资源竞争时添加的互斥锁,容易出现死锁现象,采用不多。

乐观锁

乐观锁并不是真实存在的锁,而是在更新的时候判断此时的库存是否是之前查询出的库存,如果相同,表示没人修改,可以更新库存,否则表示别人抢过资源,不再执行库存更新。类似如下操作

update tb_sku set stock=2 where id=1 and stock=7;

SKU.objects.filter(id=1, stock=7).update(stock=2)

任务队列

例如秒杀功能,将下单的逻辑放到任务队列中(如celery),将并行转为串行,所有人排队下单。比如开启只有一个进程的Celery,一个订单一个订单的处理。

使用乐观锁改写下单逻辑:

def create(self, validated_data):
        """创建订单记录:保存OrderInfo和OrderGoods信息"""

        # 获取当前保存订单时需要的信息
        # 获取当前的登录用户
        user = self.context[‘request‘].user
        # 生成订单编号
        # order_id = ‘时间‘+‘user_id‘
        # timezone.now() == datetime类型的对象
        # 20180706085001+000000001
        order_id = timezone.now().strftime(‘%Y%m%d%H%M%S‘) + (‘%09d‘ % user.id)
        # 获取地址和支付方式
        address = validated_data.get(‘address‘)
        pay_method = validated_data.get(‘pay_method‘)

        # 明显的开启事务
        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 = 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 = {b‘1‘:b‘10‘, b‘2‘:b‘20‘, b‘3‘:b‘30‘}
                redis_cart = redis_conn.hgetall(‘cart_%s‘ % user.id)
                # cart_selected = [b‘1‘, b‘2‘]
                cart_selected = redis_conn.smembers(‘selected_%s‘ % user.id)
                # 定义将来要支付的商品信息的字典
                # carts = {1:10, 2:20}
                carts = {}
                for sku_id in cart_selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])

                # 读取出所有要支付的商品的sku_id
                # sku_ids = [1,2]
                sku_ids = carts.keys()
                # 遍历购物车中被勾选的商品信息
                for sku_id in sku_ids:

                    # 死循环的下单:当库存满足,你在下单时,库存没有同时的被别人的更改,下单成功
                    # 如果下单库存被更改看,但是你的sku_count依然在被更改后的库存范围内,继续下单
                    # 直到库存真的不满足条件时才下单失败
                    while True:

                        # 获取sku对象
                        sku = SKU.objects.get(id=sku_id)

                        # 获取原始的库存和销量
                        origin_stock = sku.stock
                        origin_sales = sku.sales

                        sku_count = carts[sku_id]
                        # 判断库存?
                        if sku_count > origin_stock:
                            # 回滚
                            transaction.savepoint_rollback(save_id)
                            raise serializers.ValidationError(‘库存不足‘)

                        # 模拟网络延迟
                        import time
                        time.sleep(5)

                        # 减少库存,增加销量 SKU?
                        # sku.stock -= sku_count
                            # origin_stock = sku.stock
                            # new_stock = origin_stock - sku_count

                        # sku.sales += sku_count
                        # sku.save()

                        # 读取要更新的库存和销量
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count

                        # 使用乐观锁更新库存:在调用update()去更新库存之前,使用filter()拿着原始的库存去查询记录是否存在
                        # 如果记录不存在的,在调用update()时返回0
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if 0 == result:
                            # 死循环的下单:当库存满足,你在下单时,库存没有同时的被别人的更改,下单成功
                            # 如果下单库存被更改看,但是你的sku_count依然在被更改后的库存范围内,继续下单
                            # 直到库存真的不满足条件时才下单失败
                            continue

                        # 修改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)

                        # 下单成功要跳出死循环
                        break

                # 最后加入邮费和保存订单信息
                order.total_amount += order.freight
                order.save()
            except serializers.ValidationError:
                # 这里不会滚的原因,是因为前面已经有了回滚的动作
                raise
            except Exception:
                transaction.savepoint_rollback(save_id)
                raise # 自动的将捕获的异常抛出,不需要给异常起别名

            # 没有问题,需要明显的提交
            transaction.savepoint_commit(save_id)

            # 清除购物车中已结算的商品
            pl = redis_conn.pipeline()
            pl.hdel(‘cart_%s‘ % user.id, *sku_ids)
            pl.srem(‘selected_%s‘ % user.id, *sku_ids)
            pl.execute()

            # 响应结果
            return order

需要修改MySQL的事务隔离级别

事务隔离级别指的是在处理同一个数据的多个事务中,一个事务修改数据后,其他事务何时能看到修改后的结果。

MySQL数据库事务隔离级别主要有四种:

  • Serializable 串行化,一个事务一个事务的执行
  • Repeatable read 可重复读,无论其他事务是否修改并提交了数据,在这个事务中看到的数据值始终不受其他事务影响
  • Read committed 读取已提交,其他事务提交了对数据的修改后,本事务就能读取到修改后的数据值
  • Read uncommitted 读取为提交,其他事务只要修改了数据,即使未提交,本事务也能看到修改后的数据值。

MySQL数据库默认使用可重复读( Repeatable read),而使用乐观锁的时候,如果一个事务修改了库存并提交了事务,那其他的事务应该可以读取到修改后的数据值,所以不能使用可重复读的隔离级别,应该修改为读取已提交Read committed。

修改方法:

在orders/urls.py文件中添加路由(红色斜体):

urlpatterns = [
    # 确认订单
    url(r‘^orders/settlement/$‘, views.OrderSettlementView.as_view()),
    # 提交订单
    url(r‘^orders/$‘, views.CommitOrderView.as_view()),
]

原文地址:https://www.cnblogs.com/cl-python/p/9343966.html

时间: 2024-11-09 01:04:13

django订单部分--数据库事务的相关文章

Django 数据库事务

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

django数据库事务

数据库原子操作 举个例子: 一个消费者在一个商户里刷信用卡消费,交易正常时,银行在消费者的账户里减去相应的款项,在商户的帐户加上相应的款项.但是如果银行从消费者的账户里扣完钱之后,还未在商户的帐户里加上相应的款项时,由于某些原因,系统或者数据库出现异常了,那么此时钱已经从消费者的账户里扣除了,但是商户的账户里却没有加上相应的款项,这种情况下,最好的解决办法就是使用数据库的原子性操作,也就是数据库的事务.保证要么同时成功,要么同时失败,然后才向数据库commit. Django默认向数据库的提交方

django中数据库事务的处理

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

数据库-事务和锁

事务 所谓事务是用户定义的一个数据库操作系列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位.例如在关系数据库中,一个事务可以是一条sql语句.一组sql语句或整个程序. 给个栗子: 小IT在网上购物,其付款过程至少包括以下几步数据库操作: 更新客户所购商品的库存信息: 生成订单并且保存到数据库: 更新用户相关信息,例如购物数量等: 正常情况下,操作顺利进行,最终交易成功,那么与交易相关的所有数据库信息也成功更新.但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存

数据库事务解析

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源.通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠.一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性.一致性.隔离性和持久性)属性.事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理. 1.操

数据库事务原理与实现

一.什么是数据库事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作. 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: · 更新客户所购商品的库存信息 · 保存客户付款信息--可能包括与银行系统的交互 · 生成订单并且保存到数据库中 · 更新用户相关信息,例如购物数量等等 正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新.但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常.该顾客银行帐户存款不足等,都将导致交

数据库事务(一)

概述 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源.通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠.一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性.一致性.隔离性和持久性)属性. 操作流程 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: · 更新客户所购商品的库存信息 · 保存客

SQL 数据库事务 存储过程练习

数据库事务: 数据库事务(Database Transaction) 是指作为单个逻辑工作单元执行的一系列操作. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源. 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: 更新客户所购商品的库存信息 保存客户付款信息--可能包括与银行系统的交互 生成订单并且保存到数据库中 · 更新用户相关信息,例如购物数量等等 正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新.

数据库基础(数据库事务及存储过程的小练习)

数据库事务: 数据库事务(Database Transaction) 是指作为单个逻辑工作单元执行的一系列操作. 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源. 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: 更新客户所购商品的库存信息 保存客户付款信息--可能包括与银行系统的交互 生成订单并且保存到数据库中 · 更新用户相关信息,例如购物数量等等 正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新.