python django设计流水号生成,带访问加锁,重试

python django设计流水号生成,带访问加锁,重试

老规矩,技术发于业务,努力从于项目。

1、设计一个流水号配置表如下:
# 流水号配置表
class BaseSerialNum(BaseModel):
    serial_type = models.CharField(verbose_name="流水号类型", max_length=10, unique=True)
    prefix = models.CharField(verbose_name="流水号的前缀字符", max_length=10, blank=True, null=True)
    serial = models.IntegerField(verbose_name="流水号的序列", default=0)
    serial_digit = models.IntegerField(verbose_name="流水号的位数", default=4)
    # 默认 前缀字符 + 年月日 + 流水号
    format = models.CharField(verbose_name="流水号的格式", max_length=10, blank=True, null=True)

    class Meta:
        verbose_name = '流水号配置表'
        verbose_name_plural = verbose_name
        db_table = "base_serial_num"
2、编写函数如下:

这里django版本太低了,如果稍微高一点,可以在select_for_update 这里多定义一个变量timeout

def get_serial_num(serial_type):
    # 当前时间
    now_time = datetime.now()
    today = now_time.date()
    formatted_date = now_time.strftime('%Y%m%d')

    # 获取流水号配置信息时对数据加锁  使用FOR UPDATE语句加上排它锁,以避免并发问题
    for i in range(3):  # 重试三次
        try:
            with transaction.atomic():
                # SELECT ... FOR UPDATE 语句用于加锁,避免并发问题
                # 如果锁不可用,则等待0.3秒  如果还获取不到则抛出异常
                serial_obj = BaseSerialNum.objects.select_for_update(nowait=True).get(serial_type=serial_type)

                last_update_time = serial_obj.update_time
                serial = serial_obj.serial
                if last_update_time and last_update_time.date() == today:
                    serial += 1
                else:
                    serial = 1
                result = BaseSerialNum.objects.filter(id=serial_obj.id).update(serial=serial, update_time=now_time)
                # 未更新成功重试
                if result == 0:
                    continue

                serial_number = serial_obj.prefix + formatted_date + '{:0{length}d}'.format(serial,
                                                                                            length=serial_obj.
                                                                                            serial_digit)
                return True, serial_number
        # 如果不存在抛出异常
        except ObjectDoesNotExist:
            return False, f"流水号类型参数 {serial_type} 未定义"
        # 获取不到锁异常 等待0.3秒重试
        except OperationalError:
            time.sleep(0.3)
            continue

    # 重试3次后依然失败,返回None
    return False, None
3、编写视图类如下:
# 流水号配置
class BaseSerialNumView(BaseViewSet):
    serializer_class = BaseSerialNumSerializer
    queryset = BaseSerialNum.objects.all().order_by("-id")

    # 生成流水号接口
    @action(methods=["get"], detail=False)
    def get_serial_num(self, request):
        req_data = request.query_params.copy()

        serial_type = req_data.get("serial_type")
        if not serial_type:
            return ReturnData(msg=f"缺少流水号类型参数", code=401)

        result, data = get_serial_num(serial_type)

        if not result:
            return ReturnData(msg=f"获取失败{data}", code=402)

        return ReturnData(msg=f"获取成功", code=200, data={"serial_num": data})

打完收工 芜湖~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值