You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP CodeIgniter框架下生成带日期的序列唯一产品编码求助

解决CodeIgniter中产品编码生成带序列后缀的问题

我明白你现在的需求:要在产品上传时生成年份后两位+年中天数+三位序列的唯一编码(比如1865001、1865002),目前已经实现了前四位,现在需要补上自动递增的三位序列。下面给你一套可靠的实现方案,兼顾唯一性和并发场景。

核心思路

要生成这样的编码,关键是持久化记录每天的序列值,避免重启或并发上传时重复。步骤如下:

  1. 生成日期前缀:年份后两位 + 补零到两位的年中天数(比如2018年第65天就是1865,第5天是1805)
  2. 查询当天已使用的最大序列值,加1得到新序列
  3. 将序列补零到三位,和日期前缀拼接成完整编码
  4. 用数据库事务+锁处理并发,防止重复

具体实现(CodeIgniter模型方法)

方案1:直接基于产品表查询(适合小型系统)

在你的产品模型中添加生成编码的方法:

class Product_model extends CI_Model {
    public function get_unique_product_code() {
        // 1. 生成日期前缀:年后两位 + 补零到两位的年中天数(date('z')从0开始,所以+1)
        $year_suffix = date('y');
        $day_of_year = str_pad(date('z') + 1, 2, '0', STR_PAD_LEFT);
        $date_prefix = $year_suffix . $day_of_year;

        $this->db->trans_start(); // 开启事务处理并发

        // 2. 查询当天最大的产品编码(锁定行防止并发修改)
        $this->db->select_max('product_code');
        $this->db->like('product_code', $date_prefix, 'after');
        $this->db->from('products');
        $this->db->lock('FOR UPDATE');
        $query = $this->db->get();
        $result = $query->row();

        // 3. 计算新序列
        if (!empty($result->product_code)) {
            // 提取现有编码的序列部分(从第4位开始)
            $last_seq = substr($result->product_code, 4);
            $new_seq = str_pad((int)$last_seq + 1, 3, '0', STR_PAD_LEFT);
        } else {
            $new_seq = '001'; // 当天第一个产品,序列从001开始
        }

        $product_code = $date_prefix . $new_seq;

        $this->db->trans_complete();

        return $product_code;
    }
}

方案2:单独序列表(高并发场景更可靠)

如果你的系统上传量较大,建议创建一个单独的序列表来记录每天的序列值,避免频繁查询产品表:

  1. 先创建序列表:
CREATE TABLE daily_product_sequences (
    date_prefix VARCHAR(4) PRIMARY KEY COMMENT '日期前缀(如1865)',
    current_seq INT DEFAULT 1 COMMENT '当前序列值'
);
  1. 模型方法实现:
class Product_model extends CI_Model {
    public function get_unique_product_code() {
        $year_suffix = date('y');
        $day_of_year = str_pad(date('z') + 1, 2, '0', STR_PAD_LEFT);
        $date_prefix = $year_suffix . $day_of_year;

        $this->db->trans_start();

        // 查询当天的序列记录(加锁)
        $this->db->select('current_seq');
        $this->db->where('date_prefix', $date_prefix);
        $this->db->lock('FOR UPDATE');
        $query = $this->db->get('daily_product_sequences');

        if ($query->num_rows() > 0) {
            // 更新序列值
            $row = $query->row();
            $new_seq = $row->current_seq + 1;
            $this->db->where('date_prefix', $date_prefix);
            $this->db->update('daily_product_sequences', ['current_seq' => $new_seq]);
        } else {
            // 当天第一条记录,插入初始序列
            $new_seq = 1;
            $this->db->insert('daily_product_sequences', [
                'date_prefix' => $date_prefix,
                'current_seq' => $new_seq
            ]);
        }

        // 补零拼接成完整编码
        $product_code = $date_prefix . str_pad($new_seq, 3, '0', STR_PAD_LEFT);

        $this->db->trans_complete();

        return $product_code;
    }
}

在控制器中使用

上传产品时调用这个方法即可:

class Product_upload extends CI_Controller {
    public function index() {
        $this->load->model('Product_model');
        $product_code = $this->Product_model->get_unique_product_code();

        // 处理产品上传逻辑,将$product_code存入数据库
        $product_data = [
            'product_code' => $product_code,
            // 其他产品字段...
        ];
        $this->db->insert('products', $product_data);

        // 返回结果或跳转
    }
}

注意事项

  • date('z')返回的是从0开始的年中天数,所以必须+1才能得到正确的第N天
  • 事务和FOR UPDATE锁是为了防止多个请求同时获取相同的序列值,确保编码唯一性
  • 如果你的年中天数不需要补零(比如第5天是185而不是1805),可以去掉str_pad方法,直接用date('z') + 1拼接

内容的提问来源于stack exchange,提问作者Codecraker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:17:40