zhangqian
2023-12-08 5220cfff6d68f24875c5ce832bbe4541b9fe6639
使用雪花算法生成表id,解决数据同步表相同记录id不一致问题
1个文件已添加
6个文件已修改
182 ■■■■■ 已修改文件
go.mod 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/dashboard.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/model.go 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/procedures.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pkg/snowflake/snowflake.go 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/report_work.go 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod
@@ -41,6 +41,7 @@
    github.com/IBM/netaddr v1.5.0 // indirect
    github.com/KyleBanks/depth v1.2.1 // indirect
    github.com/ajg/form v1.5.1 // indirect
    github.com/bwmarrin/snowflake v0.3.0 // indirect
    github.com/bytedance/sonic v1.9.1 // indirect
    github.com/cespare/xxhash/v2 v2.2.0 // indirect
    github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
go.sum
@@ -64,6 +64,8 @@
github.com/apache/plc4x/plc4go v0.0.0-20230817065839-dd203446b558/go.mod h1:KC3Kj7xv0dlGb5yT1+Mz9cI9YZj1RD19cr8TyqfnBDU=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
model/dashboard.go
@@ -9,7 +9,7 @@
type (
    Dashboard struct {
        gorm.Model
        CommonModel
        Version                       string
        DeviceRunningAmount           int   //开机台数
        TotalProductionAmount         int   //总产量
model/model.go
New file
@@ -0,0 +1,24 @@
package model
import (
    "apsClient/pkg/snowflake"
    "github.com/jinzhu/gorm"
    "time"
)
type CommonModel struct {
    ID        uint `gorm:"primary_key"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time `sql:"index"`
}
func (c *CommonModel) BeforeCreate(db *gorm.DB) {
    if c.ID == 0 {
        id := snowflake.GenerateID()
        if id < 0 {
            id = snowflake.GenerateID()
        }
        c.ID = uint(id)
    }
}
model/procedures.go
@@ -12,7 +12,7 @@
type (
    Procedures struct {
        gorm.Model
        CommonModel
        ProductProcedureID string `gorm:"index;type:varchar(191);" json:"productProcedureID"` //产品工序id
        WorkOrderID        string `gorm:"index;type:varchar(191);" json:"-"`
        OrderID            string `gorm:"index;type:varchar(191);" json:"-"`
pkg/snowflake/snowflake.go
@@ -1,118 +1,62 @@
package snowflake
import (
    "errors"
    "strconv"
    "sync"
    "time"
    "apsClient/pkg/logx"
    "fmt"
    "github.com/bwmarrin/snowflake"
    "hash/fnv"
    "net"
)
const (
    CEpoch         = 1474802888000
    CWorkerIdBits  = 10 // Num of WorkerId Bits
    CSenquenceBits = 12 // Num of Sequence Bits
var Node *snowflake.Node
    CWorkerIdShift  = 12
    CTimeStampShift = 22
    CSequenceMask = 0xfff // equal as getSequenceMask()
    CMaxWorker    = 0x3ff // equal as getMaxWorkerId()
)
type IdWorker struct {
    workerId      int64
    lastTimeStamp int64
    sequence      int64
    maxWorkerId   int64
    lock          *sync.Mutex
}
func NewIdWorker(workerId int64) (iw *IdWorker, err error) {
    iw = new(IdWorker)
    iw.maxWorkerId = getMaxWorkerId()
    if workerId > iw.maxWorkerId || workerId < 0 {
        return nil, errors.New("worker not fit")
func Init(nodeId string) error {
    // Create a new Node with a Node number of 1
    var err error
    nodeIdInt, err := StringToNumber(nodeId)
    if err != nil {
        logx.Errorf("snowflake Init error:%v", err)
        return err
    }
    iw.workerId = workerId
    iw.lastTimeStamp = -1
    iw.sequence = 0
    iw.lock = new(sync.Mutex)
    return iw, nil
}
func getMaxWorkerId() int64 {
    return -1 ^ -1<<CWorkerIdBits
}
func getSequenceMask() int64 {
    return -1 ^ -1<<CSenquenceBits
}
// return in ms
func (iw *IdWorker) timeGen() int64 {
    return time.Now().UnixNano() / 1000 / 1000
}
func (iw *IdWorker) timeReGen(last int64) int64 {
    ts := time.Now().UnixNano() / 1000 / 1000
    for {
        if ts <= last {
            ts = iw.timeGen()
        } else {
            break
        }
    Node, err = snowflake.NewNode(nodeIdInt)
    if err != nil {
        logx.Errorf("snowflake NewNode error:%v", err)
        return err
    }
    return ts
    return nil
}
func (iw *IdWorker) NextId() (ts int64, err error) {
    iw.lock.Lock()
    defer iw.lock.Unlock()
    ts = iw.timeGen()
    if ts == iw.lastTimeStamp {
        iw.sequence = (iw.sequence + 1) & CSequenceMask
        if iw.sequence == 0 {
            ts = iw.timeReGen(ts)
        }
    } else {
        iw.sequence = 0
    }
    if ts < iw.lastTimeStamp {
        err = errors.New("Clock moved backwards, Refuse gen id")
func StringToNumber(input string) (int64, error) {
    hash := fnv.New32a()
    _, err := hash.Write([]byte(input))
    if err != nil {
        return 0, err
    }
    iw.lastTimeStamp = ts
    ts = (ts-CEpoch)<<CTimeStampShift | iw.workerId<<CWorkerIdShift | iw.sequence
    return ts, nil
    hashValue := int64(hash.Sum32())
    return hashValue, nil
}
func ParseId(id int64) (t time.Time, ts int64, workerId int64, seq int64) {
    seq = id & CSequenceMask
    workerId = (id >> CWorkerIdShift) & CMaxWorker
    ts = (id >> CTimeStampShift) + CEpoch
    t = time.Unix(ts/1000, (ts%1000)*1000000)
    return
}
var idGenerater, _ = NewIdWorker(0)
func GenerateId() int64 {
start:
    id, err := idGenerater.NextId()
    if err != nil {
        goto start
func GenerateID() int64 {
    if Node == nil {
        // 使用 LookupIP 获取主机的 IP 地址列表
        addrs, err := net.LookupIP("localhost")
        if err != nil {
            logx.Infof("snowflake can not generate, init error, get ip error:%v", err)
            panic(fmt.Sprintf("snowflake can not generate, init error, get ip error:%v", err))
        }
        var ip string
        // 遍历 IP 地址列表
        for _, addr := range addrs {
            // 判断 IP 地址的版本是 IPv4 还是 IPv6
            if ipNet := addr.To4(); ipNet != nil {
                ip = ipNet.String()
                fmt.Printf("IPv4 Address: %s\n", ipNet.String())
            }
        }
        err = Init(ip)
        if err != nil {
            panic(fmt.Sprintf("snowflake can not generate, init error,:%v", err))
        }
    }
    return id
}
func GenerateIdStr() string {
start:
    id, err := idGenerater.NextId()
    if err != nil {
        goto start
    }
    return strconv.FormatInt(id, 10)
    return int64(Node.Generate())
}
service/report_work.go
@@ -10,6 +10,7 @@
    "encoding/json"
    "errors"
    "github.com/jinzhu/gorm"
    "github.com/spf13/cast"
    "time"
)
@@ -65,7 +66,7 @@
        WorkerID:           params.WorkerID,
        WorkerName:         workerName,
        WorkerTime:         nowTs - startTs,
        BarCode:            snowflake.GenerateIdStr(),
        BarCode:            cast.ToString(snowflake.GenerateID()),
    }
    err = model.WithTransaction(func(db *gorm.DB) error {
        err = model.NewReportWorkSearch(db).Create(record)