跳到主要内容

GORM 与 MySQL

如何把领域对象映射为数据表?​

type ArticleRow struct {
ID int64 `gorm:"primaryKey"`
AuthorID int64 `gorm:"not null;index"`
Title string `gorm:"size:100;not null"`
Content string `gorm:"type:text;not null"`
CreatedAt time.Time
UpdatedAt time.Time
}
  • Row: 数据库表示; 与 HTTP model、领域 entity 分离;
  • 索引: 根据查询和唯一性需求设计,不因字段存在就加索引;
  • 时间: 数据库存 UTC,响应层按契约格式化;
  • migration: 生产环境使用受审查的版本化迁移,不依赖启动时无条件 AutoMigrate;

如何将数据库查询适配为 Repository?​

func (r *GormArticleRepository) FindByID(ctx context.Context, id int64) (*Article, error) {
var row ArticleRow
err := r.db.WithContext(ctx).First(&row, id).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrArticleNotFound
}
if err != nil {
return nil, fmt.Errorf("find article %d: %w", id, err)
}
return toEntity(row), nil
}

如何限制数据库连接池?​

  • SetMaxOpenConns: 限制并发数据库连接,需与实例数和数据库上限共同计算;
  • SetMaxIdleConns: 保留可复用空闲连接,减少建连开销;
  • SetConnMaxLifetime: 小于数据库或代理强制回收周期;
  • startup ping: 在 readiness 前验证连接,但不要因短暂故障无限阻塞启动;

如何替换测试中的存储依赖?​

  • Service 测试: 使用内存或 fake Repository;
  • Repository 测试: 针对真实 MySQL 兼容环境验证 SQL、索引和事务;
  • Handler 测试: 不依赖真实数据库,注入可控 Service;