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(),大幅提升批量操作效率。
    如需进一步探讨,欢迎交流!
相关推荐
静听山水1 小时前
Redis的Pipeline (管道)
数据库·redis·php
存在的五月雨1 小时前
Spring Security认证流程
java·开发语言·mysql
hzb666661 小时前
unictf2026
开发语言·javascript·安全·web安全·php
禹凕1 小时前
Python编程——进阶知识(MYSQL引导入门)
开发语言·python·mysql
JaguarJack1 小时前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端·php·服务端
ccecw10 小时前
Mysql ONLY_FULL_GROUP_BY模式详解、group by非查询字段报错
数据库·mysql
JH307310 小时前
达梦数据库与MySQL的核心差异解析:从特性到实践
数据库·mysql
YUJIANYUE11 小时前
PHP纹路验证码
开发语言·php
MZ_ZXD00113 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
Goat恶霸詹姆斯13 小时前
mysql常用语句
数据库·mysql·oracle