refactor(serial):唯一序列号生成器改进。
This commit is contained in:
parent
bfb59a3626
commit
6bf4009338
|
@ -100,6 +100,8 @@ func (pr _ParkRepository) CreatePark(ownerId string, park *model.Park) (bool, er
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
timeNow := types.Now()
|
timeNow := types.Now()
|
||||||
|
serial.StringSerialRequestChan <- 1
|
||||||
|
code := serial.Prefix("P", <-serial.StringSerialResponseChan)
|
||||||
createSql, createArgs, _ := pr.ds.
|
createSql, createArgs, _ := pr.ds.
|
||||||
Insert("park").
|
Insert("park").
|
||||||
Cols(
|
Cols(
|
||||||
|
@ -108,7 +110,7 @@ func (pr _ParkRepository) CreatePark(ownerId string, park *model.Park) (bool, er
|
||||||
"basic_pooled", "adjust_pooled", "loss_pooled", "public_pooled", "created_at", "last_modified_at",
|
"basic_pooled", "adjust_pooled", "loss_pooled", "public_pooled", "created_at", "last_modified_at",
|
||||||
).
|
).
|
||||||
Vals(goqu.Vals{
|
Vals(goqu.Vals{
|
||||||
serial.GeneratePrefixedUniqueSerialString("P"),
|
code,
|
||||||
ownerId, park.Name, tools.PinyinAbbr(park.Name),
|
ownerId, park.Name, tools.PinyinAbbr(park.Name),
|
||||||
park.Area, park.TenementQuantity, park.Capacity, park.Category,
|
park.Area, park.TenementQuantity, park.Capacity, park.Category,
|
||||||
park.MeterType, park.Region, park.Address, park.Contact, park.Phone, park.Enabled, park.PricePolicy, park.TaxRate,
|
park.MeterType, park.Region, park.Address, park.Contact, park.Phone, park.Enabled, park.PricePolicy, park.TaxRate,
|
||||||
|
@ -347,13 +349,15 @@ func (pr _ParkRepository) CreateParkBuilding(pid, name string, floor *string) (b
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
timeNow := types.Now()
|
timeNow := types.Now()
|
||||||
|
serial.StringSerialRequestChan <- 1
|
||||||
|
code := serial.Prefix("B", <-serial.StringSerialResponseChan)
|
||||||
createSql, createArgs, _ := pr.ds.
|
createSql, createArgs, _ := pr.ds.
|
||||||
Insert("park_building").
|
Insert("park_building").
|
||||||
Cols(
|
Cols(
|
||||||
"id", "park_id", "name", "floors", "enabled", "created_at", "last_modified_at",
|
"id", "park_id", "name", "floors", "enabled", "created_at", "last_modified_at",
|
||||||
).
|
).
|
||||||
Vals(goqu.Vals{
|
Vals(goqu.Vals{
|
||||||
serial.GeneratePrefixedUniqueSerialString("B"),
|
code,
|
||||||
pid, name, floor, true, timeNow, timeNow,
|
pid, name, floor, true, timeNow, timeNow,
|
||||||
}).
|
}).
|
||||||
Prepared(true).ToSQL()
|
Prepared(true).ToSQL()
|
||||||
|
|
|
@ -134,7 +134,8 @@ func (us _UserService) CreateUserAccount(user *model.User, detail *model.UserDet
|
||||||
} else {
|
} else {
|
||||||
prefix = "S"
|
prefix = "S"
|
||||||
}
|
}
|
||||||
user.Id = serial.GeneratePrefixedUniqueSerialString(prefix)
|
serial.StringSerialRequestChan <- 1
|
||||||
|
user.Id = serial.Prefix(prefix, <-serial.StringSerialResponseChan)
|
||||||
detail.Id = user.Id
|
detail.Id = user.Id
|
||||||
}
|
}
|
||||||
verifyCode := tools.RandStr(10)
|
verifyCode := tools.RandStr(10)
|
||||||
|
|
|
@ -2,75 +2,83 @@ package serial
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"electricity_bill_calc/config"
|
"electricity_bill_calc/config"
|
||||||
"electricity_bill_calc/global"
|
|
||||||
"electricity_bill_calc/logger"
|
"electricity_bill_calc/logger"
|
||||||
"electricity_bill_calc/types"
|
"electricity_bill_calc/types"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rueian/rueidis"
|
|
||||||
"github.com/samber/lo"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logger.Named("Algorithm", "Unique Serial")
|
var (
|
||||||
|
log = logger.Named("Algorithm", "Unique Serial")
|
||||||
|
SerialRequestChan = make(chan int64, 500)
|
||||||
|
StringSerialRequestChan = make(chan int64, 500)
|
||||||
|
SerialResponseChan = make(chan int64, 500)
|
||||||
|
StringSerialResponseChan = make(chan string, 500)
|
||||||
|
)
|
||||||
|
|
||||||
// 在防止服务器时间回拨的情况下,生成一个用于生成唯一编号的精简时间戳,该时间戳的起始时间为`2022-02-22 22:22:22.000000 +0800`,时间戳精确到秒。
|
func init() {
|
||||||
func generateTimestamp() int64 {
|
go func() {
|
||||||
|
var (
|
||||||
|
lastTimestamp int64 = 0
|
||||||
|
lastSerial int64 = 0
|
||||||
|
)
|
||||||
|
log.Info("唯一序列号生成服务已经启动。")
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-SerialRequestChan:
|
||||||
|
log.Info("收到生成数字型唯一序列号的请求。")
|
||||||
|
timestamp := generateTimestamp(lastTimestamp)
|
||||||
|
if timestamp != lastTimestamp {
|
||||||
|
lastSerial = 0
|
||||||
|
}
|
||||||
|
lastSerial := lastSerial + 1
|
||||||
|
uniqueId := generateSerial(timestamp, lastSerial)
|
||||||
|
SerialResponseChan <- uniqueId
|
||||||
|
lastTimestamp = timestamp
|
||||||
|
case <-StringSerialRequestChan:
|
||||||
|
log.Info("收到生成字符串型唯一序列号的请求。")
|
||||||
|
timestamp := generateTimestamp(lastTimestamp)
|
||||||
|
if timestamp != lastTimestamp {
|
||||||
|
lastSerial = 0
|
||||||
|
}
|
||||||
|
lastSerial := lastSerial + 1
|
||||||
|
uniqueId := generateStringSerial(timestamp, lastSerial)
|
||||||
|
StringSerialResponseChan <- uniqueId
|
||||||
|
lastTimestamp = timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成一个能够对抗服务器时间回拨的时间戳
|
||||||
|
func generateTimestamp(base int64) int64 {
|
||||||
for {
|
for {
|
||||||
timestamp := types.Timestamp()
|
timestamp := types.Timestamp()
|
||||||
cmds := make(rueidis.Commands, 0, 2)
|
if timestamp >= base {
|
||||||
cmds = append(cmds, global.Rd.B().Set().Key("LAST_TIMESTAMP").Value(fmt.Sprintf("%d", timestamp)).Nx().ExSeconds(1).Build())
|
|
||||||
cmds = append(cmds, global.Rd.B().Get().Key("LAST_TIMESTAMP").Build())
|
|
||||||
results := global.Rd.DoMulti(global.Ctx, cmds...)
|
|
||||||
store_res, err := lo.Last(results)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("从Redis缓存中获取上一次的时间戳失败。", zap.Error(err))
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if stored_timestamp, err := store_res.AsInt64(); err == nil && timestamp >= stored_timestamp {
|
|
||||||
return timestamp
|
return timestamp
|
||||||
} else {
|
|
||||||
log.Error("转换从Redis缓存中获取的时间戳失败。", zap.Error(err))
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成一个基于精简改进的雪花算法的数字类型唯一编号。
|
// 生成一个唯一的数字型序列号
|
||||||
func GenerateUniqueSerial() int64 {
|
func generateSerial(timestamp, serial int64) int64 {
|
||||||
for {
|
return (timestamp << 20) | ((config.ServiceSettings.HostSerial & 0xffff) << 16) | (serial & 0xffff_ffff)
|
||||||
timestamp := generateTimestamp()
|
|
||||||
cmds := make(rueidis.Commands, 0, 2)
|
|
||||||
cmds = append(cmds, global.Rd.B().Set().Key("SERIAL").Value(fmt.Sprintf("%d", 0)).Nx().ExSeconds(1).Build())
|
|
||||||
cmds = append(cmds, global.Rd.B().Incr().Key("SERIAL").Build())
|
|
||||||
results := global.Rd.DoMulti(global.Ctx, cmds...)
|
|
||||||
store_res, err := lo.Last(results)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("从Redis缓存中获取上一次的序列号失败。", zap.Error(err))
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if stored_serial, err := store_res.AsInt64(); err == nil {
|
|
||||||
return (timestamp << 20) | ((config.ServiceSettings.HostSerial & 0xffff) << 16) | (stored_serial & 0xffff_ffff)
|
|
||||||
} else {
|
|
||||||
log.Error("转换从Redis缓存中获取的序列号失败。", zap.Error(err))
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成一个基于精简改进的雪花算法的字符串类型唯一编号。
|
// 生成一个唯一的字符串型序列号
|
||||||
func GenerateUniqueSerialString() string {
|
func generateStringSerial(timestamp, serial int64) string {
|
||||||
uniqueId := GenerateUniqueSerial()
|
return fmt.Sprintf("%017d", generateSerial(timestamp, serial))
|
||||||
return fmt.Sprintf("%d", uniqueId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成一个带有前缀的基于精简改进的雪花算法的字符串类型唯一编号。
|
// 生成一个带前缀字符串的唯一字符串型序列号
|
||||||
func GeneratePrefixedUniqueSerialString(prefix string) string {
|
func Prefix(prefix string, serial interface{}) string {
|
||||||
uniqueId := GenerateUniqueSerial()
|
switch serial := serial.(type) {
|
||||||
return fmt.Sprintf("%s%d", prefix, uniqueId)
|
case int64:
|
||||||
|
return fmt.Sprintf("%s%017d", prefix, serial)
|
||||||
|
case string:
|
||||||
|
return fmt.Sprintf("%s%s", prefix, serial)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user