1. 随机数种子初始化(rand.Seed
)
当前代码每次调用函数时都会重新调用 rand.Seed
,但通常 rand.Seed
只需在程序启动时调用一次。如果多次调用会导致性能开销,甚至在极短时间内生成重复的随机数。
改进方法:将 rand.Seed
放在 init
函数中,全局初始化。
func init() {
rand.Seed(time.Now().UnixNano())
}
然后去掉函数内的 rand.Seed
调用。
2. 线程安全问题
如果代码在并发环境下运行,标准库的 math/rand
可能会导致随机数重复。建议使用 crypto/rand
或 sync
包下的锁来保证线程安全。
使用 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