Skip to content

Latest commit

 

History

History
101 lines (69 loc) · 3.55 KB

02-database-sql.md

File metadata and controls

101 lines (69 loc) · 3.55 KB

database/sql 与持久化

Go 的数据库访问以 database/sql 为中心——它是接口层,真正驱动是 pgx、modernc.org/sqlite 等。对比 JDBC + HikariCP,模型非常像,但没有 Session / 一级缓存那些 JPA 概念。

连接池在 database/sql 里

db, err := sql.Open("sqlite", path)
db.SetMaxOpenConns(10)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(time.Hour)
if err := db.PingContext(ctx); err != nil { ... }

sql.Open 不保证连得上——一定要 Ping。池参数调不好时表现和 HikariCP 误配一样:占满、泄漏、抖动。

查询与扫描

row := db.QueryRowContext(ctx, `SELECT id, title FROM tasks WHERE id = ?`, id)
var t Task
err := row.Scan(&t.ID, &t.Title)

没有「按列名自动映射」的标准能力——sqlx 补 StructScan,pgx 走自己的 API。本教程项目 14 坚持裸 database/sql,强迫你看清扫描与生命周期。

事务 + context

tx, err := db.BeginTx(ctx, nil)
defer tx.Rollback() // 提交后 Rollback 是 no-op
if _, err := tx.ExecContext(ctx, ...); err != nil { return err }
return tx.Commit()

ctx 取消会让驱动尽力中断查询。务必把 ctx 传到每一个 ExecContext/QueryContext。

迁移

用嵌入 SQL + 版本表,或 golang-migrate。对比 Flyway/Liquibase:Go 更常把迁移文件 embed 进二进制,启动时 apply。项目 14 用简单版本表演示这个思路。

ORM 光谱

工具 风格 像 Java 的
GORM 全功能 ORM JPA/Hibernate
ent Schema as code 强类型 JOOQ 感
sqlc SQL → 生成 Go 手写 SQL + 类型安全
sqlx 轻量扩展 JdbcTemplate

Go 社区对 ORM 热情低于 Java,常见理由:隐式查询难排查、接口太大、简单 CRUD 用手写更清晰。生产里 sqlc + pgx 很常见。

QueryRow 和 Query 的生命周期

  • QueryRowContext 的查询错误通常延迟到 Scan 返回。
  • QueryContext 返回 *Rows,调用方必须关闭,并在循环后检查 Rows.Err()。
  • sql.ErrNoRows 是可识别的契约,数据层可以将它映射为领域 ErrNotFound。
rows, err := db.QueryContext(ctx, query, projectID)
if err != nil {
    return nil, err
}
defer rows.Close()

for rows.Next() {
    // Scan
}
return out, rows.Err()

事务的边界

事务函数应将业务上必须同时成功的操作放在一起。不要为了“以后可能有用”就让所有查询共享一个长事务,这会扩大锁和连接占用时间。

项目 14 的用户、项目、首个任务属于一个完整用例,因此放在同一事务中。

迁移策略

教学项目可以用一份幂等 SQL 说明基本思路。当版本增多时,需要考虑:

  • 版本是否只能向前
  • 失败后如何恢复
  • 多实例是否会同时执行迁移
  • DDL 在当前数据库中是否支持事务

这些是 Flyway/Liquibase 之类工具的价值,不必在一个练习里重写它们。

练习

配套材料:题目骨架 · 参考答案

  1. 故意让事务的第三次 INSERT 失败,验证前两次没有留在数据库。
  2. 为 SetTaskDone 增加并发更新测试,观察 SQLite 锁行为。
  3. 将 :memory: 替换为临时文件,证明关闭后数据是否持久化。

上一节:HTTP 服务基础 | 下一节:API 规范与安全

配套项目:14 待办 API