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(),大幅提升批量操作效率。
    如需进一步探讨,欢迎交流!
相关推荐
香蕉大香蕉(06敬畏市场)4 分钟前
MySQL 单点详解(09)
java·数据库·mysql·面试·八股·大厂实习
程序员大雄学编程1 小时前
Linux 磁盘满了怎么排查?df / du / find 三步定位大文件
linux·运维·php
lqbzlll2 小时前
MySQL 慢查询日志开了但看不懂?从 slow_query_log 到 EXPLAIN ANALYZE 一步步定位
数据库·mysql·adb
fengci.3 小时前
CTF2困难部分
开发语言·网络·python·安全·php
风翼靓崽3 小时前
centos7以mysql为例自建yum源
数据库·mysql·adb
大黄说说3 小时前
PHP 异步怎么实现?Swoole、Workerman 使用场景对比
开发语言·php·swoole
乐橙开放平台3 小时前
跨地域监控难管理?通过 GB28181 把各地海康大华乐橙摄像头注册到云端平台
开发语言·笔记·物联网·自动化·php·音视频·智能家居
广东融科数据服务有限公司3 小时前
网络监控经常卡顿、掉线、画面模糊?一线排查问答实录
开发语言·网络·php
秋名RG4 小时前
一条 SQL 语句在 MySQL 中的执行过程详解
数据库·sql·mysql