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.UUID
,gorm
"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: ...
目前我对我的所有数据库查询(主要是 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.UUID
,gorm
"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: ...