数据库操作

数据库连接

使用database/sql包连接和配置数据库。

package main

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

func main() {
    // 配置数据库连接
    dsn := "user:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    
    // 打开数据库连接
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 测试连接
    err = db.Ping()
    if err != nil {
        panic(err)
    }
    
    // 配置连接池
    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(25)
    db.SetConnMaxLifetime(5 * time.Minute)
    
    fmt.Println("Database connected successfully")
}

基本CRUD操作

执行基本的增删改查操作。

package main

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

type User struct {
    ID       int
    Name     string
    Email    string
    Password string
}

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 创建用户
    result, err := db.Exec(
        "INSERT INTO users (name, email, password) VALUES (?, ?, ?)",
        "John Doe", "john@example.com", "password123",
    )
    if err != nil {
        panic(err)
    }
    
    // 获取插入的ID
    id, err := result.LastInsertId()
    if err != nil {
        panic(err)
    }
    
    // 查询用户
    var user User
    err = db.QueryRow("SELECT id, name, email FROM users WHERE id = ?", id).Scan(
        &user.ID, &user.Name, &user.Email,
    )
    if err != nil {
        panic(err)
    }
    
    // 更新用户
    _, err = db.Exec(
        "UPDATE users SET name = ? WHERE id = ?",
        "John Updated", id,
    )
    if err != nil {
        panic(err)
    }
    
    // 删除用户
    _, err = db.Exec("DELETE FROM users WHERE id = ?", id)
    if err != nil {
        panic(err)
    }
}

事务处理

使用事务确保数据一致性。

package main

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

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)
        }
    }()
    
    // 从账户扣除金额
    _, err = tx.Exec(
        "UPDATE accounts SET balance = balance - ? WHERE id = ?",
        amount, fromID,
    )
    if err != nil {
        tx.Rollback()
        return err
    }
    
    // 向账户增加金额
    _, err = tx.Exec(
        "UPDATE accounts SET balance = balance + ? WHERE id = ?",
        amount, toID,
    )
    if err != nil {
        tx.Rollback()
        return err
    }
    
    // 提交事务
    return tx.Commit()
}

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    err = transferMoney(db, 1, 2, 100.0)
    if err != nil {
        panic(err)
    }
}

预处理语句

使用预处理语句提高性能和安全性。

package main

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

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 准备插入语句
    stmt, err := db.Prepare("INSERT INTO users (name, email) VALUES (?, ?)")
    if err != nil {
        panic(err)
    }
    defer stmt.Close()
    
    // 执行多次插入
    users := []struct {
        name  string
        email string
    }{
        {"Alice", "alice@example.com"},
        {"Bob", "bob@example.com"},
        {"Charlie", "charlie@example.com"},
    }
    
    for _, user := range users {
        _, err = stmt.Exec(user.name, user.email)
        if err != nil {
            panic(err)
        }
    }
}

批量操作

使用批量操作提高性能。

package main

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

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 开始事务
    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }
    
    // 准备批量插入语句
    stmt, err := tx.Prepare("INSERT INTO users (name, email) VALUES (?, ?)")
    if err != nil {
        tx.Rollback()
        panic(err)
    }
    defer stmt.Close()
    
    // 批量插入数据
    for i := 0; i < 1000; i++ {
        _, err = stmt.Exec(
            fmt.Sprintf("User%d", i),
            fmt.Sprintf("user%d@example.com", i),
        )
        if err != nil {
            tx.Rollback()
            panic(err)
        }
    }
    
    // 提交事务
    err = tx.Commit()
    if err != nil {
        panic(err)
    }
}

连接池管理

优化数据库连接池配置。

package main

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

func configureConnectionPool(db *sql.DB) {
    // 设置最大打开连接数
    db.SetMaxOpenConns(25)
    
    // 设置最大空闲连接数
    db.SetMaxIdleConns(25)
    
    // 设置连接最大生命周期
    db.SetConnMaxLifetime(5 * time.Minute)
    
    // 设置空闲连接最大生命周期
    db.SetConnMaxIdleTime(10 * time.Minute)
}

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 配置连接池
    configureConnectionPool(db)
    
    // 监控连接池状态
    go func() {
        for {
            stats := db.Stats()
            fmt.Printf("Open Connections: %d\n", stats.OpenConnections)
            fmt.Printf("In Use: %d\n", stats.InUse)
            fmt.Printf("Idle: %d\n", stats.Idle)
            fmt.Printf("Wait Count: %d\n", stats.WaitCount)
            fmt.Printf("Wait Duration: %v\n", stats.WaitDuration)
            time.Sleep(time.Second)
        }
    }()
}

错误处理

处理数据库操作中的常见错误。

package main

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

func handleDBError(err error) {
    if err == sql.ErrNoRows {
        fmt.Println("No rows found")
        return
    }
    
    if err == sql.ErrConnDone {
        fmt.Println("Connection is closed")
        return
    }
    
    if err == sql.ErrTxDone {
        fmt.Println("Transaction is already committed or rolled back")
        return
    }
    
    // 处理其他错误
    fmt.Printf("Database error: %v\n", err)
}

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    // 查询不存在的记录
    var name string
    err = db.QueryRow("SELECT name FROM users WHERE id = ?", 999).Scan(&name)
    handleDBError(err)
    
    // 使用已关闭的连接
    db.Close()
    err = db.Ping()
    handleDBError(err)
    
    // 使用已提交的事务
    tx, _ := db.Begin()
    tx.Commit()
    err = tx.Commit()
    handleDBError(err)
}