Go使用sqlx操作MySQL完整指南

markdown 复制代码
# Go使用sqlx操作MySQL完整指南

## 1. 安装依赖

```bash
go get github.com/go-sql-driver/mysql
go get github.com/jmoiron/sqlx

2. 数据库基础操作

go 复制代码
package main

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

// 定义全局db对象
var db *sqlx.DB

// 用户结构体
type User struct {
    ID       int    `db:"id"`
    Username string `db:"username"`
    Password string `db:"password"`
    Age      int    `db:"age"`
}

// 初始化数据库连接
func initDB() (err error) {
    // 连接数据库
    dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True"
    db, err = sqlx.Connect("mysql", dsn)
    if err != nil {
        return err
    }
    
    // 设置连接池参数
    db.SetMaxOpenConns(100)
    db.SetMaxIdleConns(10)
    return nil
}

// 创建数据库
func createDatabase() error {
    _, err := db.Exec("CREATE DATABASE IF NOT EXISTS test DEFAULT CHARACTER SET utf8mb4")
    return err
}

// 删除数据库
func dropDatabase() error {
    _, err := db.Exec("DROP DATABASE IF EXISTS test")
    return err
}

// 创建表
func createTable() error {
    sql := `
    CREATE TABLE IF NOT EXISTS users(
        id INT PRIMARY KEY AUTO_INCREMENT,
        username VARCHAR(50) NOT NULL UNIQUE,
        password VARCHAR(50) NOT NULL,
        age INT
    )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    `
    _, err := db.Exec(sql)
    return err
}

// 删除表
func dropTable() error {
    _, err := db.Exec("DROP TABLE IF EXISTS users")
    return err
}

// 插入单条数据
func insertUser(user User) error {
    sql := "INSERT INTO users(username, password, age) VALUES (?, ?, ?)"
    _, err := db.Exec(sql, user.Username, user.Password, user.Age)
    return err
}

// 批量插入数据
func batchInsertUsers(users []User) error {
    sql := "INSERT INTO users(username, password, age) VALUES (:username, :password, :age)"
    _, err := db.NamedExec(sql, users)
    return err
}

// 查询单个用户
func getUserByID(id int) (User, error) {
    var user User
    sql := "SELECT * FROM users WHERE id=?"
    err := db.Get(&user, sql, id)
    return user, err
}

// 查询多个用户
func getUsers(age int) ([]User, error) {
    var users []User
    sql := "SELECT * FROM users WHERE age > ?"
    err := db.Select(&users, sql, age)
    return users, err
}

// 更新用户
func updateUser(user User) error {
    sql := "UPDATE users SET password=?, age=? WHERE username=?"
    _, err := db.Exec(sql, user.Password, user.Age, user.Username)
    return err
}

// 删除用户
func deleteUser(id int) error {
    sql := "DELETE FROM users WHERE id=?"
    _, err := db.Exec(sql, id)
    return err
}

func main() {
    // 初始化数据库连接
    if err := initDB(); err != nil {
        fmt.Printf("init db failed, err:%v\n", err)
        return
    }
    defer db.Close()
    
    // 创建数据库
    if err := createDatabase(); err != nil {
        fmt.Printf("create database failed, err:%v\n", err)
        return
    }
    
    // 创建表
    if err := createTable(); err != nil {
        fmt.Printf("create table failed, err:%v\n", err)
        return
    }
    
    // 插入单个用户
    user1 := User{
        Username: "张三",
        Password: "123456",
        Age:      20,
    }
    if err := insertUser(user1); err != nil {
        fmt.Printf("insert user failed, err:%v\n", err)
        return
    }
    
    // 批量插入用户
    users := []User{
        {Username: "李四", Password: "123456", Age: 21},
        {Username: "王五", Password: "123456", Age: 22},
        {Username: "赵六", Password: "123456", Age: 23},
    }
    if err := batchInsertUsers(users); err != nil {
        fmt.Printf("batch insert users failed, err:%v\n", err)
        return
    }
    
    // 查询单个用户
    user, err := getUserByID(1)
    if err != nil {
        fmt.Printf("get user failed, err:%v\n", err)
        return
    }
    fmt.Printf("user:%#v\n", user)
    
    // 查询多个用户
    userList, err := getUsers(20)
    if err != nil {
        fmt.Printf("get users failed, err:%v\n", err)
        return
    }
    fmt.Printf("users:%#v\n", userList)
    
    // 更新用户
    user1.Password = "654321"
    if err := updateUser(user1); err != nil {
        fmt.Printf("update user failed, err:%v\n", err)
        return
    }
    
    // 删除用户
    if err := deleteUser(1); err != nil {
        fmt.Printf("delete user failed, err:%v\n", err)
        return
    }
    
    // 删除表
    if err := dropTable(); err != nil {
        fmt.Printf("drop table failed, err:%v\n", err)
        return
    }
    
    // 删除数据库
    if err := dropDatabase(); err != nil {
        fmt.Printf("drop database failed, err:%v\n", err)
        return
    }
}

3. 事务操作示例

go 复制代码
// 使用事务进行转账
func transfer(fromUsername, toUsername string, amount int) error {
    tx, err := db.Beginx() // 开启事务
    if err != nil {
        return err
    }
    
    // 在事务中执行多个SQL操作
    sql1 := "UPDATE users SET balance = balance - ? WHERE username = ?"
    sql2 := "UPDATE users SET balance = balance + ? WHERE username = ?"
    
    // 执行第一个SQL
    result1, err := tx.Exec(sql1, amount, fromUsername)
    if err != nil {
        tx.Rollback() // 回滚事务
        return err
    }
    
    // 检查影响行数
    rows1, err := result1.RowsAffected()
    if err != nil {
        tx.Rollback()
        return err
    }
    if rows1 != 1 {
        tx.Rollback()
        return fmt.Errorf("转出账户不存在")
    }
    
    // 执行第二个SQL
    result2, err := tx.Exec(sql2, amount, toUsername)
    if err != nil {
        tx.Rollback()
        return err
    }
    
    // 检查影响行数
    rows2, err := result2.RowsAffected()
    if err != nil {
        tx.Rollback()
        return err
    }
    if rows2 != 1 {
        tx.Rollback()
        return fmt.Errorf("转入账户不存在")
    }
    
    // 提交事务
    return tx.Commit()
}

4. 常用查询技巧

4.1 IN查询

go 复制代码
func getUsersByIDs(ids []int) ([]User, error) {
    query, args, err := sqlx.In("SELECT * FROM users WHERE id IN (?)", ids)
    if err != nil {
        return nil, err
    }
    
    query = db.Rebind(query)
    var users []User
    err = db.Select(&users, query, args...)
    return users, err
}

4.2 分页查询

go 复制代码
func getUsersByPage(page, pageSize int) ([]User, error) {
    offset := (page - 1) * pageSize
    sql := "SELECT * FROM users LIMIT ? OFFSET ?"
    var users []User
    err := db.Select(&users, sql, pageSize, offset)
    return users, err
}

4.3 模糊查询

go 复制代码
func searchUsers(keyword string) ([]User, error) {
    sql := "SELECT * FROM users WHERE username LIKE ?"
    var users []User
    err := db.Select(&users, sql, "%"+keyword+"%")
    return users, err
}

5. 注意事项

  1. 始终记得关闭数据库连接
  2. 使用事务时要确保正确处理回滚和提交
  3. 使用预处理语句防止SQL注入
  4. 合理设置连接池参数
  5. 处理所有可能的错误
  6. 使用合适的字段类型和索引优化查询性能

6. 最佳实践

  1. 使用结构体标签映射数据库字段
  2. 统一错误处理
  3. 使用连接池
  4. 合理组织代码结构
  5. 编写单元测试
  6. 记录必要的日志
  7. 定期备份数据库
复制代码
相关推荐
Heisenberg~3 分钟前
C++回溯算法详解
开发语言·c++·算法
朴拙数科21 分钟前
Stable Diffusion秋叶整合包V4独立版Python本地API连接指南
开发语言·python·stable diffusion
苹果酱056727 分钟前
Vue3 源码解析(六):响应式原理与 reactive
java·vue.js·spring boot·mysql·课程设计
z_mazin29 分钟前
JavaScript 渲染内容爬取:Puppeteer 入门
开发语言·javascript·ecmascript
虽千万人 吾往矣30 分钟前
golang channel源码
开发语言·后端·golang
小川_wenxun44 分钟前
线程池的介绍
java·开发语言
忒可君1 小时前
QT 5.15 程序打包
开发语言·c++·qt
normaling1 小时前
十八,MyCat配置读写分离
mysql
北辰浮光1 小时前
[SpringMVC]请求响应参数传递
java·开发语言·前端