【问题标题】:GORM UUID too longGORM UUID 太长
【发布时间】:2017-05-09 07:54:21
【问题描述】:

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

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

如果用户上不存在 UUID,我正在使用 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 输出的长度,它返回为 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_id 使用二进制文件?你为什么要使用en.wikipedia.org/wiki/Universally_unique_identifier之类的东西?
  • 我可以在这里看到 stackoverflow.com/questions/15130321/… 这真的很容易生成。
  • 我一直在使用它,但我最好的猜测是全部依赖于数据库。我可以看到你有id,然后是user_id,为什么你还有user_id
  • Mysql 没有 uuid 字段。 Gorm 自己生成了 id 列。我想要一个 uuid 列,如果需要,我会考虑删除 gorm 生成的列...
  • 我问过你,如果你的用户表中的主键是id,为什么你还有user_id?你应该考虑将你的表重命名为user,因为它是一个模型。看看这里stackoverflow.com/questions/338156/…。以id 为主,user_id 在我看来是完全多余的。

标签: mysql sql go go-gorm


【解决方案1】:

我认为问题在于模型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 会将字段“误解”为字符串,然后将该字符串作为二进制插入到数据库中。比如下面这个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: ...

【讨论】:

  • 基于这个问题github.com/jinzhu/gorm/issues/1687jinzhu 建议不要使用[]byte作为类型
  • @NeXtMaN_786 这个问题专门针对 AFAIK 没有 UUID 列类型的 MySQL。您提到的问题是针对其列具有 UUID 数据类型的 PostgreSQL,并且 Go 驱动程序也支持该问题。在后一种情况下,我同意我们不应该使用[]byte 在 Golang 中存储 GUID。
猜你喜欢
  • 2013-02-07
  • 2016-07-28
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 2014-09-27
  • 1970-01-01
  • 2019-06-20
  • 1970-01-01
相关资源
最近更新 更多