Django transaction.atomic 事务的使用

函数 transaction.atomic

数据库的读写操作中,事务在保证数据的安全性和一致性方面起着关键的作用,而回滚正是这里面的核心操作。

遇到并发的时候常常会因为接口的访问顺序或者其他情况,导致数据的不一致,这时候就知道回滚的重要性了,下面有个简单的小例子 可以实现数据库事务的操作

Demo

数据库的模型和返回值窝这边就不贴出来了
这是一个接口

from django.db import transaction
import time
def keke_test(request):
    code = 1
    msg = '操作成功'

    g = request.REQUEST.post
    params = dict()
    model_id = g.get('id', '0')
    model = None
    if model_id > 0:
        model = IosSdkVersions.objects.filter(id=model_id).first()
        with transaction.atomic():  # 禁止自动提交,保证该函数中的所有数据库操作在同一个事物中,第一个数据库操作1即使成功保存到数据库中,只要第2个数据操作失败,那么所有该段代码所有设计的都会更改回滚到原来
            try:
                sdk_flag_model = IosSdkTest.objects.filter(id=1).first()
                sid = transaction.savepoint()  # 开启事务设置事务保存点
                sdk_flag_model.sdk_flag = 8
                sdk_flag_model.save() # 完成就保存,但不是马上提交
                time.sleep(10)
                all_issue_field_value = IosSdkVersions.objects.filter(id=3)
                for issue in all_issue_field_value:
                    issue.test_id = 8
                    issue.save()
                    # 1 / 0
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(sid)  # 失败回滚事务(如果数据库操作发生异常,回滚到设置的事务保存点)
                print('数据保存失败')
                code = -1001
            else:
                code = 1
                transaction.savepoint_commit(sid)  # 如果没有异常,成功提交事物

    params['code'] = code
    return json_response(params)

# 接口2,当执行第一个接口的时候,因为sleep的存在,这个操作会一直等待到第一个接口完成操作 再进行操作
def keke_test2(request):
    code = 1
    msg = '操作成功'
    _g = request.REQUEST.get
    sdk_flag_model = IosSdkTest.objects.filter(id=1).first()
    sdk_flag_model.sdk_flag = 2
    sdk_flag_model.save() # 因为被锁住了所以接口会等到上一个接口的完成
    # if sdk_flag_model.sdk_flag == 8:
        # all_issue_field_value = IosSdkVersions.objects.filter(id=3)
        # for issue in all_issue_field_value:
        #     issue.test_id -= 2
        #     issue.save()
    params = dict()
    return json_response(params)

# 接口2 other
def keke_test2(request):
    code = 1
    msg = '操作成功'
    _g = request.REQUEST.get
    sdk_flag_model = IosSdkTest.objects.filter(id=1).first()
    if not sdk_flag_model.sdk_flag == 2: # 会等到flag为2的时候才去执行下面的操作
        sdk_flag_model.sdk_flag = 3
        sdk_flag_model.save()
    params = dict()
    params['code'] = code
    return json_response(params)

# other

def keke_test2(request):
    code = 1
    msg = '操作成功'
    _g = request.REQUEST.get
    with transaction.atomic():  # 禁止自动提交,保证该函数中的所有数据库操作在同一个事物中,第一个数据库操作1即使成功保存到数据库中,只要第2个数据操作失败,那么所有该段代码所有设计的都会更改回滚到原来
        sid = transaction.savepoint()  # 开启事务设置事务保存点
        try:
            sdk_flag_model = IosSdkTest.objects.select_for_update().get(id=1) # 互扯锁的另一种实现
            sdk_flag_model.sdk_flag = 8
            sdk_flag_model.save()
            time.sleep(10)
        except Exception as e:
            print(e)
            transaction.savepoint_rollback(sid)  # 失败回滚事务(如果数据库操作发生异常,回滚到设置的事务保存点)
            print('数据保存失败')
            code = -1001
        else:
            code = 1
            transaction.savepoint_commit(sid)  # 如果没有异常,成功提交事物
    params = dict()
    params['code'] = code
    return json_response(params)

悲观锁

# 悲观锁实现, 都要放在 with transaction.atomic() 事务中 同条数据上锁完,需要等释放后才能再次上锁的吧

def keke_test2(request):
    code = 1
    msg = '操作成功'
    _g = request.REQUEST.get
    with transaction.atomic():  # 禁止自动提交,保证该函数中的所有数据库操作在同一个事物中,第一个数据库操作1即使成功保存到数据库中,只要第2个数据操作失败,那么所有该段代码所有设计的都会更改回滚到原来
        sid = transaction.savepoint()  # 开启事务设置事务保存点
        try:
            sdk_flag_model = IosSdkTest.objects.select_for_update().get(id=1)  # 互扯锁的另一种实现
            sdk_flag_model.sdk_flag = 8
            sdk_flag_model.save()
            time.sleep(10)
        except Exception as e:
            print(e)
            transaction.savepoint_rollback(sid)  # 失败回滚事务(如果数据库操作发生异常,回滚到设置的事务保存点)
            print('数据保存失败')
            code = -1001
        else:
            code = 1
            transaction.savepoint_commit(sid)  # 如果没有异常,成功提交事物
    params = dict()
    params['code'] = code
    return json_response(params)


def keke_test3(request):
    code = 1
    msg = '操作成功'
    _g = request.REQUEST.get
    with transaction.atomic():
        sdk_flag_model = IosSdkTest.objects.select_for_update().get(id=1)
        print(sdk_flag_model.sdk_flag)
    params = dict()
    params['code'] = code
    return json_response(params)

原生sql 锁的操作

参考:https://segon.cn/mysql-for-update.html

posted @ 2021-08-27 10:58  陈科科  阅读(1912)  评论(0编辑  收藏  举报