php 防伪溯源项目:防伪码生成与批量写入实践

目录

一、项目背景与防伪码要求

二、核心实现思路

三、数据库表设计(唯一性兜底)

四、16位数字防伪码生成方法

[1. 使用 ThinkPHP Helper 助手函数(推荐)](#1. 使用 ThinkPHP Helper 助手函数(推荐))

[2. 使用 FastAdmin 自带随机函数(推荐)](#2. 使用 FastAdmin 自带随机函数(推荐))

[3. 自定义随机数生成函数](#3. 自定义随机数生成函数)

五、防伪码批量生成与写入方案

[1. 简单递归生成(适合小批量)](#1. 简单递归生成(适合小批量))

[2. 批量生成唯一防伪码(MySQL查重)](#2. 批量生成唯一防伪码(MySQL查重))

[六、基于 Redis 的唯一防伪码生成](#六、基于 Redis 的唯一防伪码生成)

[七、批量写入 insertAll() 使用规范](#七、批量写入 insertAll() 使用规范)

总结


一、项目背景与防伪码要求

在防伪溯源项目中, 第一步就是创建防伪码。防伪码的设计需满足以下要求:

  • 全局唯一性
  • 16位纯数字字符串,随机生成
  • 支持高效批量写入

二、核心实现思路

  • 16位纯数字防伪码 由于PHP的int类型无法承载16位数字,直接生成字符串格式的16位数字,避免溢出丢失精度。
  • 唯一性保障 采用"预生成 + 查重 + 批量插入"方案,结合MySQL唯一索引做最终兜底,双重防止重复。
  • 高效批量插入 整理符合模型要求的二维数组,使用ThinkPHP模型的insertAll()高效插入,兼顾性能和框架规范。

三、数据库表设计(唯一性兜底)

确保防伪码字段为字符串类型,并添加唯一索引,防止重复:

php 复制代码
CREATE TABLE `fa_secure_code` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `batch_no` varchar(32) DEFAULT '' COMMENT '批次',
  `secure_code` varchar(32) DEFAULT '' COMMENT '防伪码',
  `goods_id` int(11) DEFAULT NULL COMMENT '商品ID',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态 1正常 0 禁用',
  `create_date` datetime DEFAULT NULL COMMENT '创建时间',
  `update_date` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_secure_code` (`secure_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='防伪码';

四、16位数字防伪码生成方法

1. 使用 ThinkPHP Helper 助手函数(推荐)

php 复制代码
// 安装依赖
composer require topthink/think-helper
// 生成随机字符串
$code =  Str::random(16, 1);

2. 使用 FastAdmin 自带随机函数(推荐)

php 复制代码
$code = Random::numeric(16);

3. 自定义随机数生成函数

php 复制代码
function random_number(int $length = 16)
{
    $str = '';
    for ($i = 0; $i < $length; $i++) {
        $str .= random_int(0, 9);
    }
    return $str;
}

五、防伪码批量生成与写入方案

1. 简单递归生成(适合小批量)

php 复制代码
public static function createSecureCode(): string
{
    $str = Str::random(16, 1);
    $find = SecureCode::where('secure_code', $str)->find();
    if ($find) {
        return self::createSecureCode();
    }
    return $str;
}

public static function batchAdd($count, $goodsId)
{
    $batch = date('YmdHis');
    for ($i = 0; $i < $count; ++$i) {
        transaction(function () use ($batch, $goodsId) {
            $data = [
                'batch_no' => $batch,
                'goods_id' => $goodsId,
                'status' => 1,
                'secure_code' => SecureCode::createSecureCode(),
            ];
            $secure = SecureCode::create($data);
        });
    }
}

2. 批量生成唯一防伪码(MySQL查重)

核心逻辑:

  • 批量生成16位数字字符串
  • 查重去重
  • 整理数据格式
  • insertAll()批量插入,处理唯一索引冲突
php 复制代码
public static function batchAddV2($count, $goodsId)
{
    // 初步生成
    $code_list = SecureCode::getCodeList($count);
    // 过滤重复的code
    $ux_code_list = SecureCode::filterCodes($code_list);

    while (\count($ux_code_list) < $count) {
        $need_count = $count - \count($ux_code_list);
        $_code_list = SecureCode::getCodeList($need_count);
        $_ux_code_list = SecureCode::filterCodes($_code_list);
        $ux_code_list = array_merge($ux_code_list, $_ux_code_list);
        $ux_code_list = array_unique($ux_code_list);
    }

    $ux_code_list = \array_slice($ux_code_list, 0, $count);
}

public static function getCodeList(int $count, array $list = [])
{
    $origin_count = \count($list);
    $target_count = $count - $origin_count;
    for ($i = 0; $i < $target_count; ++$i) {
        $list[] = Str::random(16, 1);
    }
    $list = array_unique($list);

    if (\count($list) < $count) {
        return self::getCodeList($count, $list);
    }

    return \array_slice($list, 0, $count);
}

/**
 * 过滤重复的code
 */
public static function filterCodes($code_list)
{
    $codes = self::whereIn('bar_code', $code_list)->column('bar_code');
    return array_filter($code_list, function ($code) use ($codes) {
        return !\in_array($code, $codes);
    });
}

六、基于 Redis 的唯一防伪码生成

核心优势:

  • Redis Set 天然去重:SADD命令自动忽略重复,无需手动查重。
  • 内存级高效操作:所有操作均在内存中,效率远高于MySQL的WHERE IN查询。
  • 原子性保障:单线程模型,避免高并发下的重复。
  • 双重兜底安全:Redis Set去重 + MySQL唯一索引兜底。
    实现示例:
php 复制代码
public static function batchAddV3($count, $goodsId)
{
    $key = 'secure_code_list_set';

    // 1. 数据一致性同步(兜底,避免Redis数据丢失)
    $current_count = redis_utils()->sCard($key);
    if (!$current_count) {
        SecureCode::field('id,secure_code')
            ->chunk(1000, function ($list) use ($key) {
                $dbCodes = array_column($list, 'secure_code');
                redis_utils()->sAdd($key, ...$dbCodes);
            });
    }

    $code_list = SecureCode::getCodeList($count);
    $ux_code_list = SecureCode::redisFilterCodes($key, $code_list);

    while (\count($ux_code_list) < $count) {
        $need_count = $count - \count($ux_code_list);
        $_code_list = SecureCode::getCodeList($need_count);
        $_ux_code_list = SecureCode::redisFilterCodes($key, $_code_list);
        $ux_code_list = array_merge($ux_code_list, $_ux_code_list);
        $ux_code_list = array_unique($ux_code_list);
    }
}

public static function redisFilterCodes($key, $code_list)
{
    foreach ($code_list as $index => $code) {
        if (redis_utils()->sIsMember($key, $code)) {
            unset($code_list[$index]);
        }
    }
    return array_unique($code_list);
}

七、批量写入 insertAll() 使用规范

使用ThinkPHP模型的insertAll()进行批量插入:

php 复制代码
$data = [];
$batch = date('YmdHis');
for ($i = 0; $i < $count; ++$i) {
    $data[] = [
        'batch_no' => $batch,
        'goods_id' => $goodsId,
        'status' => 1,
        'secure_code' => $ux_code_list[$i],
        'create_date' => date('Y-m-d H:i:s'),
        'update_date' => date('Y-m-d H:i:s'),
    ];
}

SecureCode::insertAll($data);

总结

  • 防伪码生成需保证唯一性高效性,推荐使用字符串存储和唯一索引兜底。
  • 批量生成时可结合MySQL查重或Redis Set天然去重,提升性能。
  • 最终插入建议使用insertAll(),大幅提升批量操作效率。
    如需进一步探讨,欢迎交流!
相关推荐
爪哇天下3 小时前
Mysql实现经纬度距离的排序(粗略的城市排序)
数据库·mysql
独自破碎E3 小时前
MySQL中有哪些日志类型?
数据库·mysql
小唐同学爱学习3 小时前
短链接修改之写锁
spring boot·redis·后端·mysql
luoluoal4 小时前
基于python的web渗透测试工具(源码+文档)
python·mysql·django·毕业设计·源码
007php0074 小时前
mac笔记本中在PHP中调用Java JAR包的指南
java·ide·python·面试·职场和发展·pycharm·php
袁煦丞 cpolar内网穿透实验室6 小时前
mysql_exporter+cpolar远程监控 MySQL 不卡壳!cpolar 内网穿透实验室第 712 个成功挑战
服务器·数据库·mysql·远程工作·内网穿透·cpolar
Mikhail_G6 小时前
Mysql数据库操作指南(零基础篇二)
大数据·数据库·sql·mysql·数据分析
酉鬼女又兒7 小时前
SQL16 查找GPA最高值
数据库·sql·mysql
陌上丨7 小时前
MVCC的原理是什么?谈谈你的理解!
数据库·mysql