GORM UUID 太长

GORM UUID too long

目前我对我的所有数据库查询(主要是 CRUD)都使用 GO-GORM,我在将生成的 UUID 插入 MySQL 数据库列时遇到了一些问题。

该列是多个博客中建议的 BINARY(16),UUID 是使用 github.com/satori/go.uuid 包生成的 Golang。

我正在使用 GORM 的 BeforeCreate 挂钩生成 UUID(如果用户不存在),我使用的代码如下:

func (u *User) BeforeCreate(scope *gorm.Scope) (err error) {
    if u.UserID == uuid.Nil {
        uuid, err := uuid.NewV4().MarshalBinary()
        scope.SetColumn("user_id", uuid)
    }
}

我还使用 len 来获取 MarshalBinary 输出的长度,它 returns 为 16。

我在尝试将 UUID 插入 MySQL 时从 GORM 得到的错误如下:

(Error 1406: Data too long for column 'user_id' at row 1)

我也fmt.Println(uuid) 看到了结果,它们也如下(随着每次插入生成 UUID 的明显变化)

[93 132 59 55 102 96 72 35 137 185 34 21 195 88 213 127]

我的MYSQL架构也如下:

CREATE TABLE users
(
    id INT(10) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    deleted_at TIMESTAMP,
    user_id BINARY(16) NOT NULL,
    username VARCHAR(255) NOT NULL,
    password VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    email VARCHAR(255),
    address_id VARCHAR(255)
);
CREATE INDEX idx_users_deleted_at ON users (deleted_at);
CREATE UNIQUE INDEX username ON users (username);
CREATE UNIQUE INDEX user_id ON users (user_id);

我尝试了不同的方法和库来生成 UUID 并将它们转换为二进制文件以插入,结果相似。

我认为问题出在模型的定义上User。要将 GUID 保存为 16 字节二进制文件,您需要将 UserID 列定义为 []byte 而不是 uuid.UUID.

type User struct {
    //other fields ..
    UserID    []byte

    //other fields ...
}

func (u *User) BeforeCreate(scope *gorm.Scope) (err error) {
    if u.UserID == nil {
        uuid, err := uuid.NewV4().MarshalBinary()
        scope.SetColumn("user_id", uuid)
    }
    return nil
}

如果将字段定义为 uuid.UUIDgorm "misinterpreted" 将字段定义为字符串,然后将该字符串以二进制形式插入数据库。比如下面的UUID,

uuid: 16ac369b-e57f-471b-96f6-1068ead0bf98
//16-bytes equivalent
bytes: [22 172 54 155 229 127 71 27 150 246 16 104 234 208 191 152]

将作为 UUID 的 ASCII 代码插入到数据库中

0x31 0x36 0x61 0x63 0x33 0x36 0x39 0x62 0x2D 0x65 ...
('1' '6'  'a'  'c'  '3'  '6'  '9'  'b'  '-'  'e'  ...)

长度为 36 个字节,因此您得到 Error 1406: ...