怎样实现一个按天递增的mysql字段,大佬们帮忙想想有没有好的解决方案

需求:需要一个按日自增的字段,这个字段的规则为 日期+递增量,且每日归零。

举例:今日第一条记录该字段值为 202203251,然后今日第二条记录为202203252,以此类推。然后明天第一条记录为202203261,明天第二条记录为202203262 …

目前我自己能想到的方案有两种:

  1. 第一种方案:每次插入数据时先在PHP里查询出最新的一条mysql记录,然后在PHP里计算出下一条记录的字段值应该为多少。

  2. 第二种方案:利用mysql事件(定时任务)和mysql自定义函数。

但是我感觉这两种方案都太麻烦,不知道大佬们有没有什么好的方案,欢迎讨论^ ^

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 12

把问题简单化,你只需要一个每天的计数。按这个思路考虑下

2年前 评论
清风 (楼主) 2年前
porygonCN 2年前

意义何在? 新增一个新的字段 替换他就好

2年前 评论
清风 (楼主) 2年前

redis 的 incr 命令了解一下 用日期做为 key

2年前 评论

...简单点,数据库只存储一个计数,再设置linux定时任务每日零点置零

2年前 评论

第一个方案感觉还可以,维护简单,但可能同时插入时的数据重复,是否还需要加锁或者unique_key来处理异常。 我想到的是利用另一个表的主键自增的特点来返回值,可能避免重复记录的情况,但这样维护成本高些

public function getNumber()  {
        $date = date('Ymd');//20220325
        // 插入新行返回递增的主键,可能是20220324..或20220325..
        $number = DB::table('tests')->insertGetId([]);
        //如果是20220325..递增的,直接返回
        if (substr($number,0,8) == $date) {
            return $this->format($number);
        }
        //否则重新设定自增主键
        // DB::table('tests')->delete();
        $newStart = DB::table('tests')->insertGetId([
            'id' => $date * 10000 + 1 //202203250001
        ]);
        return $this->format($newStart);
    }
    //202203250001 转成 202203251
    public function format($number) {
        $str = substr($number, 0, 8) . substr($number,8)/1;
        return (int)$str;
    }
2年前 评论
清风 (楼主) 2年前
clyde-cn

我猜你需要这个

/**
     * 生成客户礼券的批次号
     * @param string $prefix
     * @param int $length
     * @return string
     */
    public static function generate_batch_no($prefix='',$length=6): string
    {
        $Redis = Cache::store('redis')->handler();
        $currentCycle = date('Ymd',time()); // 日期拼接成中间
        $key = "codegen:{$currentCycle}:bn"; // 生成redis健  健名前缀按照天来更新
        $codeNum = $Redis->incr($key);  // 这里用incr 方法来获取当前自增数量 incr是原子性的 能处理并发
        // 为1说明是当天的第一条,设置有效期,删除过期key
        if ($codeNum == 1) {
            // 设置有效期1天
            $expireAt = strtotime(date('Y-m-d 00:00:00', strtotime("+1 day")));
            $Redis->set($key,$codeNum,$expireAt);
            // 删除过期key,加锁,一周期只删一次 setnx锁设置键不存在则设置并返回1,否则返回0
            if ($Redis->setnx("codegen:{$currentCycle}:rmLockBn", 1)) {
                $lastCycle = date('Ymd', strtotime("-1 day"));
                $keys = $Redis->keys("codegen:{$lastCycle}:bn");
                foreach ($keys as $k) {
                    $Redis->del($k);
                }
            }
        }

        return $prefix .$currentCycle. str_pad($codeNum, $length, '0', STR_PAD_LEFT);
    }
2年前 评论
clyde-cn (作者) 2年前

你要的只是一个当天的最大计数,两条SQL语句就搞定了吧!

  1. insert into day_count(year,month,day,max) values(2022,03,26,1) ON DUPLICATE KEY UPDATE max = max+1

  2. select year,month,day,max from day_count where year = 2022 and month = 03 and day = 26

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!