PHP CodeIgniter框架下生成带日期的序列唯一产品编码求助
解决CodeIgniter中产品编码生成带序列后缀的问题
我明白你现在的需求:要在产品上传时生成年份后两位+年中天数+三位序列的唯一编码(比如1865001、1865002),目前已经实现了前四位,现在需要补上自动递增的三位序列。下面给你一套可靠的实现方案,兼顾唯一性和并发场景。
核心思路
要生成这样的编码,关键是持久化记录每天的序列值,避免重启或并发上传时重复。步骤如下:
- 生成日期前缀:年份后两位 + 补零到两位的年中天数(比如2018年第65天就是
1865,第5天是1805) - 查询当天已使用的最大序列值,加1得到新序列
- 将序列补零到三位,和日期前缀拼接成完整编码
- 用数据库事务+锁处理并发,防止重复
具体实现(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:单独序列表(高并发场景更可靠)
如果你的系统上传量较大,建议创建一个单独的序列表来记录每天的序列值,避免频繁查询产品表:
- 先创建序列表:
CREATE TABLE daily_product_sequences ( date_prefix VARCHAR(4) PRIMARY KEY COMMENT '日期前缀(如1865)', current_seq INT DEFAULT 1 COMMENT '当前序列值' );
- 模型方法实现:
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
相关产品推荐
相关产品推荐

