Go: 标准库 database
1 · 标准库 database#
1.1 · 核心设计
database/sql 包的核心思想:用户代码只依赖 sql 包,驱动实现 driver 接口,两者通过注册机制连接。
调用 调用接口
用户代码 ───────────► sql包 ───────────► driver包
▲ ▲
注册 │ 实现接口 │
└──── 驱动实现 ──────┘
好处:
- sql 包统一处理 Go 类型与 DB 类型转换,驱动只处理小部分类型
- sql 包内置连接池,并发安全,
sql.DB可在多个 goroutine 间共享 - 复杂度封装在 sql/driver 内,不暴露给用户
1.2 · sql.DB — 不是连接,是连接池#
import (
"database/sql"
_ "github.com/go-sql-driver/mysql" // 驱动 init() 中调用 sql.Register 注册
)
// Open 只验证参数,不创建连接(延迟连接)
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
defer db.Close()
1.3 · 三个核心操作
1.3.1 · 查询 — Query → Rows → Scan#
rows, err := db.QueryContext(ctx, "SELECT id, name FROM users WHERE id = ?", 1)
defer rows.Close()
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
}
err = rows.Err() // 检查迭代中的错误
1.3.2 · 修改 — Exec → Result#
result, err := db.ExecContext(ctx, "INSERT INTO users(name) VALUES(?)", "Dolly")
lastID, _ := result.LastInsertId()
affected, _ := result.RowsAffected()
1.3.3 · 事务 — Begin → Tx → Commit/Rollback#
tx, err := db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable})
_, err = tx.Exec(`UPDATE users SET status = ? WHERE id = ?`, "paid", 37)
if err != nil {
tx.Rollback()
return
}
tx.Commit()
事务期间绑定一个连接,Commit/Rollback 后连接回归空闲池。
1.4 · driver 包 — 核心接口层次#
Driver
▲
│
Conn
▲ ▲
│ │
Tx Stmt
▲ ▲
│ │
Result Rows
| 接口 | 职责 |
|---|---|
Driver / DriverContext | 打开连接 |
Connector | 带 context 创建连接 |
Conn | Prepare, Close, Begin |
Stmt | Exec, Query, Close |
Rows | Columns, Next, Close |
Result | LastInsertId, RowsAffected |
Tx | Commit, Rollback |
1.5 · 所学
面向接口编程 — 只依赖抽象的接口,不依赖具体的实现。