1. 随机数种子初始化rand.Seed

当前代码每次调用函数时都会重新调用 rand.Seed,但通常 rand.Seed 只需在程序启动时调用一次。如果多次调用会导致性能开销,甚至在极短时间内生成重复的随机数。

改进方法:将 rand.Seed 放在 init 函数中,全局初始化。

func init() {
    rand.Seed(time.Now().UnixNano())
}

然后去掉函数内的 rand.Seed 调用。


2. 线程安全问题

如果代码在并发环境下运行,标准库的 math/rand 可能会导致随机数重复。建议使用 crypto/randsync 包下的锁来保证线程安全。

使用 crypto/rand 生成随机数示例:

import (
    "crypto/rand"
    "math/big"
)

func GenerateCryptoRandomNum(max int64) int64 {
    num, _ := rand.Int(rand.Reader, big.NewInt(max))
    return num.Int64()
}

替换原来的随机数生成逻辑,避免并发问题。


3. ID 唯一性

如果交易系统对唯一性要求极高,可以使用 UUID 或 Snowflake 算法代替纯时间戳与随机数的组合。标准库没有直接支持 UUID,可以使用第三方库(如 github.com/google/uuid)。

示例:

import "github.com/google/uuid"

func GenerateUUIDTradeID() string {
    return uuid.New().String() // 生成类似 "550e8400-e29b-41d4-a716-446655440000" 的唯一 ID
}

4. 格式验证

GenerateTradeIDWithPrefix 中,建议对 prefix 参数进行校验,避免传入非法字符或过长的前缀。

示例:

func GenerateTradeIDWithValidatedPrefix(prefix string) string {
    if len(prefix) > 10 { // 限制前缀长度
        prefix = prefix[:10]
    }
    prefix = strings.ToUpper(prefix) // 转换为大写,统一格式
    return prefix + GenerateTradeID()
}

5. 日志记录和排查

在生产环境中,建议对生成的交易 ID 进行日志记录,以便在出现问题时进行排查。例如,可以在生成后将 ID 写入日志文件或数据库。


综合改进后的代码

以下是结合以上优化后的完整代码:

package utils

import (
    "crypto/rand"
    "fmt"
    "math/big"
    "strings"
    "time"
)

func init() {
    // 全局初始化随机数种子
    rand.Seed(time.Now().UnixNano())
}

// GenerateTradeID 生成交易ID (年月日时分秒 + 6位随机数)
func GenerateTradeID() string {
    now := time.Now()
    randomNum := generateCryptoRandom(1000000) // 使用安全随机数
    return fmt.Sprintf("%s%06d", now.Format("20060102150405"), randomNum)
}

// GenerateTradeIDWithPrefix 生成带前缀的交易ID
func GenerateTradeIDWithPrefix(prefix string) string {
    if len(prefix) > 10 {
        prefix = prefix[:10]
    }
    return strings.ToUpper(prefix) + GenerateTradeID()
}

// GenerateUniqueTradeID 生成唯一的交易ID(年月日时分秒纳秒 + 4位随机数)
func GenerateUniqueTradeID() string {
    now := time.Now()
    randomNum := generateCryptoRandom(10000) // 使用安全随机数
    return fmt.Sprintf("%s%d%04d",
        now.Format("20060102150405"),
        now.Nanosecond()/1000, // 纳秒转换为微秒
        randomNum,
    )
}

// 生成加密安全的随机数
func generateCryptoRandom(max int64) int64 {
    num, _ := rand.Int(rand.Reader, big.NewInt(max))
    return num.Int64()
}

示例运行

func main() {
    fmt.Println("基础交易ID:", GenerateTradeID())
    fmt.Println("带前缀交易ID:", GenerateTradeIDWithPrefix("TR"))
    fmt.Println("唯一交易ID:", GenerateUniqueTradeID())
}

输出示例

基础交易ID: 20240315142159123456
带前缀交易ID: TR20240315142159123456
唯一交易ID: 20240315142159123456789
每日更新-免费小火箭账号
不要错过任何机会,探索最新的应用和游戏,就在我们的平台。
立即访问
最后修改:2024 年 12 月 30 日
如果觉得我的文章对你有用,请随意赞赏