gorm.open 连不上数据库因 v2 版本弃用字符串 dsn,须用对应驱动的 dialector(如 postgres.new);dsn 缺 sslmode=disable 或 mysql 缺 parsetime=true&loc=local 会导致连接失败或 time.time 零值。

gorm.Open 为什么连不上数据库?
GORM v2 的 gorm.Open 不再接受字符串 DSN,必须用驱动对应的 gorm.Dialector。直接传 "host=... user=..." 会 panic:"unsupported driver: postgres" 或静默失败。
- PostgreSQL 要用
postgres.New()(来自gorm.io/driver/postgres) - MySQL 用
mysql.New()(gorm.io/driver/mysql) - SQLite 用
sqlite.Open()(gorm.io/driver/sqlite)
DSN 本身也容易错:PostgreSQL 要求 user=xxx password=xxx dbname=xxx host=xxx port=xxx sslmode=disable,漏掉 sslmode=disable 在本地开发时大概率连不上;MySQL 的 parseTime=true&loc=Local 忘加会导致 time.Time 字段读出来是零值。
Book 和 BorrowRecord 的关联怎么写才不翻车?
GORM 不自动建外键约束,也不强制要求 struct tag 匹配数据库字段。常见翻车点:
-
BorrowRecord里写BookID uint,但没加gorm:"foreignKey:BookID",GORM 会默认找BookId(驼峰)字段,查不到关联数据 -
Book的主键不是ID(比如叫book_id),但没在 struct 上声明gorm:"primaryKey",GORM 仍按ID查,关联失效 - 用
Preload("Book")查借阅记录时,如果Book表里有软删除字段deleted_at,默认会把已软删的书也一起查出来——得显式加Unscoped()或改用Joins("JOIN books ON ...").Select(...)
借书接口里事务为什么没回滚?
db.Transaction() 只在函数返回非 nil error 时回滚。但很多人写成:
立即学习“go语言免费学习笔记(深入)”;
err := db.Transaction(func(tx *gorm.DB) error {
tx.Create(&borrow)
tx.Model(&book).Update("stock", gorm.Expr("stock - 1"))
return nil // ← 这里忘了 return err!
})
更隐蔽的是:中间调用了另一个封装好的函数,它内部用了自己的 db 实例(不是事务 tx),那这条 SQL 就根本不在事务里。
- 所有操作必须用传入的
tx对象,不能混用外部db - 更新库存建议用
SELECT ... FOR UPDATE配合Row()查询,否则高并发下可能超借——GORM 的Update不带条件检查,stock减成负数也不会报错
API 返回 JSON 时 time.Time 字段总是空字符串
GORM 默认用 time.Time,但 Go 的 json.Marshal 对其序列化依赖 time.Time.MarshalJSON,而它的默认格式是 RFC 3339(带时区)。如果前端只认 "2024-01-01" 这种,后端又没统一处理,就会看到空串或解析失败。
- 不要全局改
time.Time的 JSON 方法(影响太大) - 在 struct tag 里加
json:"borrowed_at,omitempty,time_zone=Asia/Shanghai"不生效——GORM 不读这个 - 正确做法:定义自定义类型,比如
type LocalTime time.Time,实现MarshalJSON(),然后在 model 里用它替代time.Time - 或者更轻量:API 层用
map[string]interface{}手动转,把time.Time格式化成字符串再塞进去
时间格式、事务边界、关联加载方式——这三个地方出问题,系统上线后第一周就容易被压测打穿。










