沙滩星空的博客沙滩星空的博客

Go语言使用database/sql标准库操作主流的关系型数据库

简介

Go语言标准库 database/sql,提供统一的数据库操作接口,支持连接池管理、事务控制、预处理语句等核心功能。开发者通过该库的通用接口(如sql.Open、db.Query,db.Exec)操作不同数据库,无需关心底层差异。

各数据库驱动实现

  • MySQL:github.com/go-sql-driver/mysql
  • PostgreSQL:github.com/lib/pq
  • SQLite:github.com/mattn/go-sqlite3
  • SQL Server:github.com/denisenkom/go-mssqldb
  • Oracle: github.com/godror/godror

数据库连接和设置

  1. 默认启用连接池,避免频繁创建/销毁连接。
  2. 合理设置 MaxOpenConns 避免数据库过载,MaxIdleConns 减少连接重建开销。
  3. 监控指标:通过数据库的 SHOW PROCESSLIST 或驱动提供的统计接口观察连接使用情况。
import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

// 连接数据库
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")

// 这个很少用。是关闭整个连接池。
defer db.Close()

连接池设置:

db.SetMaxOpenConns(100)  // 最大活跃连接数
db.SetMaxIdleConns(10)   // 最大空闲连接数
db.SetConnMaxLifetime(time.Hour) // 连接最大存活时间

Ping 机制:通过 db.Ping() 验证数据库连通性。

if err := db.Ping(); err != nil {
    log.Fatal("数据库连接失败:", err)
}

查询数据

  1. db.Query():执行 SELECT 查询,返回 *sql.Rows。
  2. db.QueryRow():执行单行查询,返回 *sql.Row。

注:必须关闭 RowsStmt。忘记 rows.Close()stmt.Close() 可能会导致连接池耗尽。

rows, _ := db.Query("SELECT id, name FROM users")
defer rows.Close() // 必须关闭释放资源
for rows.Next() {
    var id int
    var name string
    rows.Scan(&id, &name) // 按列顺序扫描到变量
}
if err = rows.Err(); err != nil { // 检查遍历错误
    // 处理错误
}

新增和更新数据

  • db.Exec() :执行 INSERT/UPDATE/DELETE 等非查询操作。

事务

封装事务接口(BeginTx、Commit、Rollback),通过 db.Begin()db.BeginTx() 开启事务。

隔离级别:通过 db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) 设置。

tx, _ := db.Begin()
_, err1 := tx.Exec("UPDATE account SET balance = balance - 100 WHERE id = 1")
_, err2 := tx.Exec("UPDATE account SET balance = balance + 100 WHERE id = 2")
if err1 != nil || err2 != nil {
    tx.Rollback() // 回滚
} else {
    tx.Commit()   // 提交
}

预处理语句

预处理语句,统一使用 ? 占位符。如下所示:

db.Query("SELECT * FROM users WHERE id = ? AND age > ?", 123, 18)

PostgreSQL 驱动(如 lib/pq 或 pgx)会自动将 ? 转换为 $1, $2, $3 ...

使用预处理语句有如下优势:

  1. SQL注入 :通过占位符(? 或 $1)绑定参数,自动转义输入。
  2. 性能提升:数据库预编译 SQL,重复执行时效率更高。
stmt, _ := db.Prepare("INSERT INTO users(name) VALUES(?)")
defer stmt.Close()
names := []string{"Alice", "Bob"}
for _, name := range names {
    stmt.Exec(name)
}
未经允许不得转载:沙滩星空的博客 » Go语言使用database/sql标准库操作主流的关系型数据库

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址