Golang SQL编程指南

最近在学习Golang操作数据库,想请教下大家:在使用database/sql包时有哪些需要注意的性能优化点?比如连接池配置、预处理语句使用等方面。另外对于复杂查询的场景,有没有推荐的ORM框架或者更高效的查询方案?

2 回复

推荐使用database/sql包和驱动(如pqgo-sqlite3)。建议使用预处理语句防注入,结合context控制超时。推荐使用sqlx简化数据映射。注意连接池配置和错误处理。

更多关于Golang SQL编程指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang SQL编程指南

Go语言提供了database/sql包来操作SQL数据库,这是一个通用接口,需要配合特定数据库驱动使用。

1. 安装数据库驱动

// MySQL驱动
go get -u github.com/go-sql-driver/mysql

// PostgreSQL驱动  
go get -u github.com/lib/pq

// SQLite驱动
go get -u github.com/mattn/go-sqlite3

2. 连接数据库

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    // MySQL连接示例
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()
    
    // 验证连接
    err = db.Ping()
    if err != nil {
        panic(err.Error())
    }
}

3. 基本CRUD操作

查询数据

type User struct {
    ID   int
    Name string
    Age  int
}

// 单行查询
func getUser(db *sql.DB, id int) (*User, error) {
    var user User
    err := db.QueryRow("SELECT id, name, age FROM users WHERE id = ?", id).
        Scan(&user.ID, &user.Name, &user.Age)
    if err != nil {
        return nil, err
    }
    return &user, nil
}

// 多行查询
func getUsers(db *sql.DB) ([]User, error) {
    rows, err := db.Query("SELECT id, name, age FROM users")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var users []User
    for rows.Next() {
        var user User
        err := rows.Scan(&user.ID, &user.Name, &user.Age)
        if err != nil {
            return nil, err
        }
        users = append(users, user)
    }
    return users, nil
}

插入数据

func insertUser(db *sql.DB, name string, age int) (int64, error) {
    result, err := db.Exec("INSERT INTO users (name, age) VALUES (?, ?)", name, age)
    if err != nil {
        return 0, err
    }
    return result.LastInsertId()
}

更新数据

func updateUser(db *sql.DB, id int, name string, age int) error {
    _, err := db.Exec("UPDATE users SET name = ?, age = ? WHERE id = ?", name, age, id)
    return err
}

删除数据

func deleteUser(db *sql.DB, id int) error {
    _, err := db.Exec("DELETE FROM users WHERE id = ?", id)
    return err
}

4. 事务处理

func transferMoney(db *sql.DB, fromID, toID int, amount float64) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }

    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p)
        } else if err != nil {
            tx.Rollback()
        } else {
            err = tx.Commit()
        }
    }()

    // 扣款
    _, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, fromID)
    if err != nil {
        return err
    }

    // 存款
    _, err = tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", amount, toID)
    return err
}

5. 预处理语句

func batchInsertUsers(db *sql.DB, users []User) error {
    stmt, err := db.Prepare("INSERT INTO users (name, age) VALUES (?, ?)")
    if err != nil {
        return err
    }
    defer stmt.Close()

    for _, user := range users {
        _, err := stmt.Exec(user.Name, user.Age)
        if err != nil {
            return err
        }
    }
    return nil
}

6. 连接池配置

db.SetMaxOpenConns(25)      // 最大连接数
db.SetMaxIdleConns(5)       // 最大空闲连接数
db.SetConnMaxLifetime(5 * time.Minute) // 连接最大生命周期

最佳实践

  1. 总是检查错误并处理
  2. 使用defer关闭连接和资源
  3. 使用预处理语句防止SQL注入
  4. 合理配置连接池参数
  5. 在事务中处理相关操作
  6. 使用结构体映射查询结果

这个指南涵盖了Go语言SQL编程的主要方面,帮助你安全高效地进行数据库操作。

回到顶部