温馨提示×

Go语言在Linux中的数据库操作指南

小樊
33
2025-12-16 08:31:34
栏目: 编程语言

Go语言在Linux中的数据库操作指南

一 环境准备与驱动选择

  • 安装数据库:在 Debian/Ubuntu 使用 sudo apt install mysql-serverCentOS/RHEL 使用 sudo yum install mysql-server 安装 MySQLPostgreSQL 可用系统包管理器安装并启动服务。完成后用 mysql -u root -ppsql 验证。
  • 安装 Go 驱动:
    • MySQL:go get -u github.com/go-sql-driver/mysql
    • PostgreSQL:常用 github.com/lib/pq(database/sql 接口)或高性能的 pgx v5go get github.com/jackc/pgx/v5
  • 核心依赖:Go 标准库 database/sql 提供统一接口,配合具体驱动即可操作多种关系型数据库。

二 连接与初始化

  • 使用标准库 database/sql 打开连接,注意 sql.Open 并不会立即建立物理连接,需 db.Ping() 验证;通过 DSN(数据源名称)配置连接参数。
  • 示例(MySQL):
    • DSN 建议:"user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    • 连接池常用参数:SetMaxOpenConnsSetMaxIdleConnsSetConnMaxLifetime
  • 示例(PostgreSQL):
    • lib/pq DSN:"user=postgres dbname=test sslmode=disable"
    • pgx 连接:pgx.Connect(context.Background(), "postgres://user:pass@localhost/db")
  • 建议用环境变量管理敏感信息(如 DB_USER、DB_PASS、DB_HOST、DB_NAME)。

三 常见数据库快速上手

  • MySQL 最小可用示例(含连接池与查询)
    package main
    
    import (
        "database/sql"
        "fmt"
        "log"
        "time"
    
        _ "github.com/go-sql-driver/mysql"
    )
    
    func main() {
        dsn := "root:password@tcp(127.0.0.1:3306)/go_demo?charset=utf8mb4&parseTime=True&loc=Local"
        db, err := sql.Open("mysql", dsn)
        if err != nil { log.Fatal(err) }
        defer db.Close()
    
        if err = db.Ping(); err != nil { log.Fatal(err) }
        fmt.Println("Connected to MySQL")
    
        // 连接池
        db.SetMaxOpenConns(25)
        db.SetMaxIdleConns(25)
        db.SetConnMaxLifetime(5 * time.Minute)
    
        var id int
        var name string
        err = db.QueryRow("SELECT id, name FROM users WHERE id = ?", 1).Scan(&id, &name)
        if err != nil {
            if err == sql.ErrNoRows {
                log.Println("No rows")
            } else {
                log.Fatal(err)
            }
            return
        }
        fmt.Printf("User: %d, %s\n", id, name)
    }
    
  • PostgreSQL 最小可用示例(lib/pq)
    package main
    
    import (
        "database/sql"
        "fmt"
        "log"
    
        _ "github.com/lib/pq"
    )
    
    func main() {
        dsn := "postgres://postgres:12345678@localhost/mydb?sslmode=disable"
        db, err := sql.Open("postgres", dsn)
        if err != nil { log.Fatal(err) }
        defer db.Close()
    
        if err = db.Ping(); err != nil { log.Fatal(err) }
        fmt.Println("Connected to PostgreSQL")
    
        var version string
        err = db.QueryRow("SELECT version()").Scan(&version)
        if err != nil { log.Fatal(err) }
        fmt.Println("PG version:", version)
    }
    
  • 要点:使用参数化查询(?$1)防止 SQL 注入QueryRow().Scan() 处理单行;rows.Next() 流式遍历结果集并在最后检查 rows.Err()

四 CRUD 与事务

  • 插入、更新、删除:使用 db.Exec();通过 LastInsertId() 获取自增主键,通过 RowsAffected() 获取影响行数。
  • 查询:单行用 QueryRow(),多行用 Query() 配合 rows.Scan();务必在循环后检查 rows.Err()
  • 事务:使用 db.Begin() 获取事务对象 tx,在错误时 tx.Rollback(),成功时 tx.Commit();复杂场景可用保存点(Savepoint)实现细粒度回滚。
  • 示例(事务转账)
    tx, err := db.Begin()
    if err != nil { log.Fatal(err) }
    defer func() {
        if p := recover(); p != nil { tx.Rollback(); panic(p) }
    }()
    _, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100, 1)
    if err != nil { tx.Rollback(); return }
    _, err = tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", 100, 2)
    if err != nil { tx.Rollback(); return }
    if err = tx.Commit(); err != nil { log.Fatal(err) }
    
  • 建议:对高频重复语句使用 Prepare 提升性能与安全性;对批量写入使用事务减少提交开销。

五 生产实践与排错要点

  • 连接池与性能:根据 QPS/并发 调整 MaxOpenConns(如 CPU 核数的 2–3 倍)、MaxIdleConns(约为 MaxOpenConns 的 50%)、ConnMaxLifetime(如 30 分钟–2 小时);通过 db.Stats() 监控连接状态。
  • 配置与安全:
    • MySQL DSN 使用 utf8mb4parseTime=True&loc=Local 正确处理字符与时区;
    • 凭证使用环境变量或配置中心管理,避免硬编码;
    • 远程访问 PostgreSQL 时,修改 postgresql.conflisten_addressespg_hba.conf 并重启服务。
  • 错误处理:区分 sql.ErrNoRows 与数据库特定错误(如 MySQL 错误码 1062 唯一键冲突);必要时实现指数退避重试。
  • 迁移与可维护性:使用 golang-migrate 管理版本化迁移;为关键路径 SQL 建立索引、用 EXPLAIN 分析执行计划;分页优先 键集分页 提升大表性能。
  • 监控与日志:集成 Prometheus 指标(如查询耗时直方图)与慢查询日志,便于定位瓶颈。

0