Gorm 使用问题大全
仅记录已经遇到的问题,其他问题请参考 Gorm 官方文档。
Error 1170 (42000): BLOB/TEXT column 'userId' used in key specification without a key length
背景
使用 gorm 连接 mysql 时,执行 AutoMigrate 方法时出现错误:
Error 1170 (42000): BLOB/TEXT column 'userId' used in key specification without a key length创建数据库表的SQL如下,添加了 userId 字段作为唯一索引:
CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
`userId` varchar(253) NOT NULL DEFAULT '' COMMENT '用户 ID',
`username` varchar(253) NOT NULL DEFAULT '' COMMENT '用户名称',
`status` tinyint(3) unsigned NOT NULL DEFAULT 1 COMMENT '用户状态,0-禁用;1-启用',
`nickname` varchar(253) NOT NULL DEFAULT '' COMMENT '用户昵称',
`password` varchar(64) NOT NULL DEFAULT '' COMMENT '用户加密后的密码',
`email` varchar(253) NOT NULL DEFAULT '' COMMENT '用户电子邮箱',
`phone` varchar(16) NOT NULL DEFAULT '' COMMENT '用户手机号',
`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_user_id` (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';在使用 Go 编码时,我是使用了 gen-gorm-models 来生成 gorm 模型, 生成的 Model 定义如下:
// UserM 用户表
type UserM struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:主键 ID" json:"id"` // 主键 ID
UserID string `gorm:"column:userId;not null;comment:用户 ID" json:"userId"` // 用户 ID
Username string `gorm:"column:username;not null;comment:用户名称" json:"username"` // 用户名称
Status *int32 `gorm:"column:status;not null;default:1;comment:用户状态,0-禁用;1-启用" json:"status"` // 用户状态,0-禁用;1-启用
Nickname string `gorm:"column:nickname;not null;comment:用户昵称" json:"nickname"` // 用户昵称
Password string `gorm:"column:password;not null;comment:用户加密后的密码" json:"password"` // 用户加密后的密码
Email string `gorm:"column:email;not null;comment:用户电子邮箱" json:"email"` // 用户电子邮箱
Phone string `gorm:"column:phone;not null;comment:用户手机号" json:"phone"` // 用户手机号
CreatedAt *time.Time `gorm:"column:createdAt;not null;default:current_timestamp;comment:创建时间" json:"createdAt"` // 创建时间
UpdatedAt *time.Time `gorm:"column:updatedAt;not null;default:current_timestamp;comment:最后修改时间" json:"updatedAt"` // 最后修改时间
}可以看到,gorm tag 没有指定 userId 字段的长度(即 varchar(64)),导致 mysql 报错。
解决方法
修改代码生成工具的代码,将 FieldWithTypeTag 由 false 改为 true,重新生成模型即可。
FieldWithTypeTag:设置为true,自动从数据库获取字段类型和长度信息。
Error 1292 (22007): Incorrect datetime value: '0000-00-00' for column 'createdAt' at row 1
错误信息
error: code = 500 reason = UserCreateFailed message = create user failed: Error 1292 (22007): Incorrect datetime value: '0000-00-00' for column 'createdAt' at row 1 metadata = map[] cause = <nil>背景
使用 gorm 连接 mysql 时,insert 数据时,createdAt 字段没有设置 value,导致报错。
创建数据库表的 sql 如下,添加了 createdAt 字段的默认值为当前时间。
CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
`userId` varchar(253) NOT NULL DEFAULT '' COMMENT '用户 ID',
`username` varchar(253) NOT NULL DEFAULT '' COMMENT '用户名称',
`status` tinyint(3) unsigned NOT NULL DEFAULT 1 COMMENT '用户状态,0-禁用;1-启用',
`nickname` varchar(253) NOT NULL DEFAULT '' COMMENT '用户昵称',
`password` varchar(64) NOT NULL DEFAULT '' COMMENT '用户加密后的密码',
`email` varchar(253) NOT NULL DEFAULT '' COMMENT '用户电子邮箱',
`phone` varchar(16) NOT NULL DEFAULT '' COMMENT '用户手机号',
`createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_user_id` (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';在使用 Go 编码时,我是使用了 gen-gorm-models 来生成 gorm 模型, 生成的 Model 定义如下:
type UserM struct {
ID int64 `gorm:"column:id;type:bigint unsigned;primaryKey;autoIncrement:true;comment:主键 ID" json:"id"` // 主键 ID
UserID string `gorm:"column:userId;type:varchar(253);not null;comment:用户 ID" json:"userId"` // 用户 ID
Username string `gorm:"column:username;type:varchar(253);not null;comment:用户名称" json:"username"` // 用户名称
Status int32 `gorm:"column:status;type:tinyint unsigned;not null;default:1;comment:用户状态,0-禁用;1-启用" json:"status"` // 用户状态,0-禁用;1-启用
Nickname string `gorm:"column:nickname;type:varchar(253);not null;comment:用户昵称" json:"nickname"` // 用户昵称
Password string `gorm:"column:password;type:varchar(64);not null;comment:用户加密后的密码" json:"password"` // 用户加密后的密码
Email string `gorm:"column:email;type:varchar(253);not null;comment:用户电子邮箱" json:"email"` // 用户电子邮箱
Phone string `gorm:"column:phone;type:varchar(16);not null;comment:用户手机号" json:"phone"` // 用户手机号
CreatedAt time.Time `gorm:"column:createdAt;type:datetime;not null;default:current_timestamp;comment:创建时间" json:"createdAt"` // 创建时间
UpdatedAt time.Time `gorm:"column:updatedAt;type:datetime;not null;default:current_timestamp;comment:最后修改时间" json:"updatedAt"` // 最后修改时间
}运行代码,调用 CreateUser 方法,报错如下:
error: code = 500 reason = UserCreateFailed message = create user failed: Error 1292 (22007): Incorrect datetime value: '0000-00-00' for column 'createdAt' at row 1 metadata = map[] cause = <nil>查看程序日志,发现是在调用 CreateUser 方法时,createdAt 字段的值为 0001-01-01T00:00:00Z,导致 mysql 报错。
Failed to insert object into database {"object": {"id":1,"userId":"user-droan9","username":"art","status":1,"nickname":"art","password":"$2a$10$KDmXsFSZg6.WQHo/BcYn3ewWxnMCRGuxjbekxrMTfD3FDzHnXiyCW","email":"[email protected]","phone":"13800000000","createdAt":"0001-01-01T00:00:00Z","updatedAt":"2025-11-06T15:30:13.359+08:00"}, "error": "Error 1292 (22007): Incorrect datetime value: '0000-00-00' for column 'createdAt' at row 1"}那么如何解决这个问题呢?
解决方法
查看官方文档的约定,GORM使用字段 CreatedAt 和 UpdatedAt 来自动跟踪记录的创建和更新时间。
所以创建数据库表时我们不再设置默认值为当前时间,而是在代码中由 gorm 自动设置。
CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键 ID',
`userId` varchar(253) NOT NULL DEFAULT '' COMMENT '用户 ID',
`username` varchar(253) NOT NULL DEFAULT '' COMMENT '用户名称',
`status` tinyint(3) unsigned NOT NULL DEFAULT 1 COMMENT '用户状态,0-禁用;1-启用',
`nickname` varchar(253) NOT NULL DEFAULT '' COMMENT '用户昵称',
`password` varchar(64) NOT NULL DEFAULT '' COMMENT '用户加密后的密码',
`email` varchar(253) NOT NULL DEFAULT '' COMMENT '用户电子邮箱',
`phone` varchar(16) NOT NULL DEFAULT '' COMMENT '用户手机号',
`createdAt` datetime NOT NULL COMMENT '创建时间',
`updatedAt` datetime NOT NULL COMMENT '最后修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_user_id` (`userId`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';生成的 GORM Model 中,CreatedAt 和 UpdatedAt 字段的类型为 time.Time,gorm 会自动将其设置为当前时间。
type UserM struct {
ID int64 `gorm:"column:id;type:bigint unsigned;primaryKey;autoIncrement:true;comment:主键 ID" json:"id"` // 主键 ID
UserID string `gorm:"column:userId;type:varchar(253);not null;comment:用户 ID" json:"userId"` // 用户 ID
Username string `gorm:"column:username;type:varchar(253);not null;comment:用户名称" json:"username"` // 用户名称
Status int32 `gorm:"column:status;type:tinyint unsigned;not null;default:1;comment:用户状态,0-禁用;1-启用" json:"status"` // 用户状态,0-禁用;1-启用
Nickname string `gorm:"column:nickname;type:varchar(253);not null;comment:用户昵称" json:"nickname"` // 用户昵称
Password string `gorm:"column:password;type:varchar(64);not null;comment:用户加密后的密码" json:"password"` // 用户加密后的密码
Email string `gorm:"column:email;type:varchar(253);not null;comment:用户电子邮箱" json:"email"` // 用户电子邮箱
Phone string `gorm:"column:phone;type:varchar(16);not null;comment:用户手机号" json:"phone"` // 用户手机号
CreatedAt time.Time `gorm:"column:createdAt;type:datetime;not null;comment:创建时间" json:"createdAt"` // 创建时间
UpdatedAt time.Time `gorm:"column:updatedAt;type:datetime;not null;comment:最后修改时间" json:"updatedAt"` // 最后修改时间
}最后,调用 CreateUser 方法,即可成功创建用户。
AutoMigrate 和 索引管理
查看官方文档
使用 AutoMigrate 会创建表、缺失的外键、约束、列和索引。 It will change existing column’s type if its size, precision changed, or if it’s changing from non-nullable to nullable.
当手动创建表的索引,并且使用了 gorm gen 包自动生成 Model 代码,那么需要配置 FieldWithIndexTag 为 true,否则会出现索引丢失问题。