GORM UUID太长

huangapple go评论87阅读模式
英文:

GORM UUID too long

问题

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

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

我使用GORM的BeforeCreate钩子来在用户不存在UUID时生成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并将其转换为二进制以进行插入,但结果相似。

英文:

Currently I am using GO-GORM for all of my database queries (mostly CRUD) and I am having some issues inserting a generated UUID into a MySQL database column.

The column is a BINARY(16) as suggested in multiple blogs, the UUID is generated using github.com/satori/go.uuid package for Golang.

I am using GORM's BeforeCreate hook to generate the UUID if one does not already exist on the user, the code that I am using is as follows:

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

I have also used len to get the length that MarshalBinary outputs and it returns as 16.

The error I get from GORM when trying to insert the UUID into MySQL is as follows:

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

I have also fmt.Println(uuid) to see the results and they are also as follows (obviosuly changes as the UUID is generated every insert)

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

My MYSQL schema is as follows also:

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);

I have tried different methods and libraries to generate UUIDs and convert them to binary to insert with similar results.

答案1

得分: 4

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

type User struct {
    //其他字段...
    UserID    []byte
    
    //其他字段...
}

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: [22 172 54 155 229 127 71 27 150 246 16 104 234 208 191 152]

将以UUID的ASCII码形式插入数据库,这些ASCII码是:

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

这些ASCII码的长度为36字节,因此你会遇到Error 1406: ...的错误。

英文:

I think the problem is in the definition of model User. To save the GUID as 16-bytes binary, you need to define the UserID column as []byte not 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
}

If you define the field as uuid.UUID, gorm "misinterpreted" the field as string and then insert that string into the database as binary. For example, the following 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]

will be inserted to database as the ASCII codes of the UUID which are

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

which are 36-bytes in length, thus you're getting Error 1406: ...

huangapple
  • 本文由 发表于 2017年5月8日 21:09:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/43848535.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定