mysql

command
v0.0.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2025 License: MIT Imports: 6 Imported by: 0

README

MySQL 数据库示例

本示例展示了如何使用 Kit 的 MySQL 数据库模块,实现基本的数据库 CRUD 操作和事务处理。

功能特性

  • 支持单行和多行数据查询
  • 支持数据插入、更新和删除操作
  • 支持事务处理和自动回滚
  • 支持结构化的错误处理
  • 支持日志记录和监控

设计原理

Kit 的 MySQL 数据库示例采用了以下设计:

  • 使用结构体定义数据模型
  • 函数式编程风格,每个操作独立封装
  • 统一的错误处理和日志记录
  • 事务操作的安全处理机制
  • 资源的自动释放(defer)

使用方法

1. 编译和运行

在 Unix/Linux/macOS 系统上:

# 添加执行权限
chmod +x build.sh

# 构建和运行
./build.sh
2. 代码示例
数据模型定义
// User 用户表结构。
//
// 字段说明:
//   - ID:用户唯一标识,主键,自增。
//   - Name:用户名称。
//   - Age:用户年龄。
type User struct {
    ID   int64  `db:"id"`
    Name string `db:"name"`
    Age  int    `db:"age"`
}
单行数据查询
// queryRow 查询单条数据示例。
func queryRow(db *sql.DB, _ kitlog.Logger, id int64) (*User, error) {
    // 构造查询 SQL 语句。
    sqlStr := "SELECT `id`, `name`, `age` FROM `example_user` WHERE `id` = ? LIMIT 1;"
    var u User
    // 执行查询并扫描结果到结构体。
    err := db.QueryRow(sqlStr, id).Scan(&u.ID, &u.Name, &u.Age)
    if err != nil {
        return nil, err
    }
    return &u, nil
}
多行数据查询
// queryMultiRow 查询多条数据示例。
func queryMultiRow(db *sql.DB, logger kitlog.Logger) ([]*User, error) {
    // 构造查询 SQL 语句。
    sqlStr := "SELECT `id`, `name`, `age` FROM `example_user` WHERE `id` > ? LIMIT 65535;"
    // 执行查询。
    rows, err := db.Query(sqlStr, 0)
    if err != nil {
        return nil, err
    }
    // 确保结果集被正确关闭。
    defer func() {
        if err := rows.Close(); err != nil {
            logger.Error(err)
        }
    }()

    var users []*User
    // 遍历结果集。
    for rows.Next() {
        var u User
        // 扫描当前行到结构体。
        err := rows.Scan(&u.ID, &u.Name, &u.Age)
        if err != nil {
            return nil, err
        }
        users = append(users, &u)
    }
    return users, nil
}
数据插入
// insertRow 插入数据示例。
func insertRow(db *sql.DB, _ kitlog.Logger, user *User) (int64, error) {
    var sqlStr string
    var args []interface{}

    // 根据是否指定 ID 构造不同的插入语句。
    if user.ID > 0 {
        sqlStr = "INSERT INTO `example_user`(`id`, `name`, `age`) VALUES (?, ?, ?);"
        args = []interface{}{user.ID, user.Name, user.Age}
    } else {
        sqlStr = "INSERT INTO `example_user`(`name`, `age`) VALUES (?, ?);"
        args = []interface{}{user.Name, user.Age}
    }

    // 执行插入操作。
    ret, err := db.Exec(sqlStr, args...)
    if err != nil {
        return 0, err
    }
    // 获取插入记录的 ID。
    theID, err := ret.LastInsertId()
    if err != nil {
        return 0, err
    }
    return theID, nil
}
数据更新
// updateRow 更新数据示例。
func updateRow(db *sql.DB, _ kitlog.Logger, user *User) (int64, error) {
    // 构造更新 SQL 语句。
    sqlStr := "UPDATE `example_user` SET `age`=? WHERE `id` = ? LIMIT 1;"
    // 执行更新操作。
    ret, err := db.Exec(sqlStr, user.Age, user.ID)
    if err != nil {
        return 0, err
    }
    // 获取受影响的行数。
    n, err := ret.RowsAffected()
    if err != nil {
        return 0, err
    }
    return n, nil
}
数据删除
// deleteRow 删除数据示例。
func deleteRow(db *sql.DB, _ kitlog.Logger, id int64) (int64, error) {
    // 构造删除 SQL 语句。
    sqlStr := "DELETE FROM `example_user` WHERE `id` = ? LIMIT 1;"
    // 执行删除操作。
    ret, err := db.Exec(sqlStr, id)
    if err != nil {
        return 0, err
    }
    // 获取受影响的行数。
    n, err := ret.RowsAffected()
    if err != nil {
        return 0, err
    }
    return n, nil
}
事务处理
// transactionDemo 事务操作示例。
func transactionDemo(db *sql.DB, logger kitlog.Logger) error {
    // 开始事务。
    tx, err := db.Begin()
    if err != nil {
        return fmt.Errorf("开始事务失败:%w", err)
    }

    // 使用 defer 处理事务回滚,确保在返回错误时一定会回滚。
    committed := false
    defer func() {
        if !committed {
            if err := tx.Rollback(); err != nil {
                logger.Error(fmt.Errorf("回滚事务失败:%w", err))
            }
        }
    }()

    // 首先检查记录是否存在。
    var exists1, exists2 bool
    // 检查 ID 为 2 的记录是否存在。
    err = tx.QueryRow("SELECT EXISTS(SELECT 1 FROM `example_user` WHERE `id` = ?)", 2).Scan(&exists1)
    if err != nil {
        return fmt.Errorf("检查表 `example_user` 中第一条记录是否存在失败:%w", err)
    }
    // 检查 ID 为 3 的记录是否存在。
    err = tx.QueryRow("SELECT EXISTS(SELECT 1 FROM `example_user` WHERE `id` = ?)", 3).Scan(&exists2)
    if err != nil {
        return fmt.Errorf("检查表 `example_user` 中第二条记录是否存在失败:%w", err)
    }

    // 如果任一记录不存在,返回错误。
    if !exists1 || !exists2 {
        return fmt.Errorf("表 `example_user` 中部分记录不存在:`id=2` 存在=%v,`id=3` 存在=%v", exists1, exists2)
    }

    // 更新第一条记录。
    sqlStr1 := "UPDATE `example_user` SET `age`=30 WHERE `id`=? LIMIT 1;"
    ret1, err := tx.Exec(sqlStr1, 2)
    if err != nil {
        return fmt.Errorf("执行表 `example_user` 第一次更新失败:%w", err)
    }
    // 获取第一次更新影响的行数。
    affRow1, err := ret1.RowsAffected()
    if err != nil {
        return fmt.Errorf("获取第一次更新影响行数失败:%w", err)
    }

    // 更新第二条记录。
    sqlStr2 := "UPDATE `example_user` SET `age`=40 WHERE `id`=? LIMIT 1;"
    ret2, err := tx.Exec(sqlStr2, 3)
    if err != nil {
        return fmt.Errorf("执行表 `example_user` 第二次更新失败:%w", err)
    }
    // 获取第二次更新影响的行数。
    affRow2, err := ret2.RowsAffected()
    if err != nil {
        return fmt.Errorf("获取第二次更新影响行数失败:%w", err)
    }

    // 检查更新是否都成功,如果成功则提交事务。
    if affRow1 == 1 && affRow2 == 1 {
        if err := tx.Commit(); err != nil {
            return fmt.Errorf("提交事务失败:%w", err)
        }
        committed = true
        return nil
    }

    return fmt.Errorf("更新影响的行数不正确:第一次=%d,第二次=%d", affRow1, affRow2)
}

注意事项

  • 所有 SQL 语句都使用参数绑定,防止 SQL 注入
  • 查询结果集使用 defer 确保正确关闭
  • 事务操作使用 defer 确保正确回滚
  • 错误处理使用 fmt.Errorf 包装原始错误
  • 更新和删除操作使用 LIMIT 1 限制影响范围
  • 使用 RowsAffected 检查操作影响的行数

相关文档

许可证

本示例代码采用 MIT 许可证。详见 LICENSE 文件。

Documentation

Overview

Package main 演示了如何使用 fsyyft-go/kit 包中的 MySQL 数据库连接功能。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL