From 8a039094cff84857c7cea02795599a10008c43da Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 26 Aug 2025 16:34:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20base=20=E6=B7=BB=E5=8A=A0=E6=82=B2?= =?UTF-8?q?=E8=A7=82=E9=94=81=E5=8F=8A=E5=85=B6=E8=A3=85=E9=A5=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/utils/lock.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 apps/utils/lock.py diff --git a/apps/utils/lock.py b/apps/utils/lock.py new file mode 100644 index 00000000..58b4caaa --- /dev/null +++ b/apps/utils/lock.py @@ -0,0 +1,51 @@ +from contextlib import contextmanager +from rest_framework.exceptions import ParseError +from functools import wraps +from django.db import transaction + +@contextmanager +def lock_model_record(model_class, pk): + """ + Locks a model instance and returns it. + """ + try: + instance = model_class.objects.select_for_update().get(pk=pk) + yield instance + except model_class.DoesNotExist: + raise ParseError("该记录不存在或已被删除") + +def lock_model_record_d_func(model_class, pk_attr='id'): + """ + 通用模型锁装饰器(内置事务),用于装饰函数 + """ + def decorator(func): + @wraps(func) + @transaction.atomic + def wrapper(old_instance, *args, **kwargs): + try: + # 获取新鲜记录 + fresh_record = model_class.objects.select_for_update().get(pk=getattr(old_instance, pk_attr)) + # 调用原函数,但传入新鲜记录 + return func(fresh_record, *args, **kwargs) + except model_class.DoesNotExist: + raise ParseError('记录不存在或已被删除') + return wrapper + return decorator + +def lock_model_record_d_method(model_class, pk_attr='id'): + """ + 通用模型锁装饰器(内置事务), 用于装饰类方法 + """ + def decorator(func): + @wraps(func) + @transaction.atomic + def wrapper(self, old_instance, *args, **kwargs): + try: + # 获取新鲜记录 + fresh_record = model_class.objects.select_for_update().get(pk=getattr(old_instance, pk_attr)) + # 调用原函数,但传入新鲜记录 + return func(self, fresh_record, *args, **kwargs) + except model_class.DoesNotExist: + raise ParseError('记录不存在或已被删除') + return wrapper + return decorator \ No newline at end of file