Go语言中使用 sqlx 来操作 MySQL

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Go语言因其高效的性能和简洁的语法而受到开发者们的欢迎。在开发过程中,数据库操作不可或缺。虽然Go的标准库提供了`database/sql`包支持数据库操作,但使用起来稍显复杂。为此,`sqlx`应运而生,作为`database/sql`的扩展库,它简化了许多常见的数据库任务。本文介绍如何使用`sqlx`包操作MySQL数据库,包括安装所需的包、连接数据库、创建表、插入/查询/更新/删除数据等操作,并展示了如何利用命名参数来进一步简化代码。通过`sqlx`,开发者可以更加高效且简洁地完成数据库交互任务。

Go 语言以其高效和简洁的语法逐渐受到开发者的青睐。在实际开发中,数据库操作是不可避免的任务之一。虽然标准库提供了 database/sql 包来支持数据库操作,但使用起来略显繁琐。

sqlx 包作为一个扩展库,它在 database/sql 的基础上,提供了更高级别的便利,极大地简化了数据库操作。本文章将介绍如何通过 github.com/jmoiron/sqlx 包来操作 MySQL 数据库。

准备工作

首先,确保你的 Go 环境已经搭建完毕,并且 MySQL 数据库已安装并正在运行。接下来,安装 sqlx 包及 MySQL 驱动:

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

连接 MySQL 数据库

在使用数据库之前,我们需要建立与 MySQL 的连接。在 Go 语言中,通常使用一个连接字符串来指定数据库的一些信息。以下是一个示例代码,演示如何连接 MySQL 数据库:

package main

import (
    "fmt"

    _ "github.com/go-sql-driver/mysql" // 一定不能忘记导入数据库驱动
    "github.com/jmoiron/sqlx"
)

var db *sqlx.DB

type User struct {
   
    ID   int64  `db:"id"`
    Name string `db:"name"`
    Age  int    `db:"age"`
}

func initDB() (err error) {
   
    dsn := "root:123456@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"
    // 也可以使用 MustConnect 连接不成功就直接 panic
    // db = sqlx.MustConnect("mysql", dsn)
    db, err = sqlx.Connect("mysql", dsn)
    if err != nil {
   
        fmt.Printf("connect DB failed, err:%v\n", err)
        return
    }
    db.SetMaxOpenConns(20) // 设置数据库连接池的最大连接数
    db.SetMaxIdleConns(10) // 设置数据库连接池的最大空闲连接数
    return
}

在这个例子中,请替换为你自己的MySQL 配置。

数据库操作

1. 创建表

接下来,让我们创建一个示例表。我们可以使用 Exec 方法执行 SQL 语句来创建表。

func CreateTable(db *sqlx.DB) (err error) {
   
    // 写SQL语句
    sqlStr := `create table if not exists users (
        id bigint primary key auto_increment,
        name varchar(20),
        age int default 1
    );`
    _, err = db.Exec(sqlStr)

    return err
}

main 函数中调用 CreateTable(db),以确保在连接后创建表。

2. 插入数据

// 插入用户并获取 ID
func insertUser(db *sqlx.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
    }

    id, err := result.LastInsertId()
    if err != nil {
   
        return 0, err
    }
    return id, nil
}

3. 查询数据

// 查询单条用户记录
func getUser(db *sqlx.DB, id int64) (*User, error) {
   
    var user User
    err := db.Get(&user, "SELECT * FROM users WHERE id=?", id)
    if err != nil {
   
        return nil, err
    }
    return &user, nil
}

// 查询所有用户记录
func getAllUsers(db *sqlx.DB, id int64) ([]User, error) {
   
    var users []User
    err := db.Select(&users, "SELECT * FROM users where id > ?", id)
    if err != nil {
   
        return nil, err
    }
    return users, nil
}

4. 更新数据

// 更新用户信息
func updateUser(db *sqlx.DB, id int64, name string, age int) (int64, error) {
   
    result, err := db.Exec("UPDATE users SET name=?, age=? WHERE id=?", name, age, id)
    if err != nil {
   
        return 0, err
    }
    rowsAffected, err := result.RowsAffected()
    if err != nil {
   
        return 0, err
    }
    return rowsAffected, nil
}

5. 删除数据

// 删除用户记录
func deleteUser(db *sqlx.DB, id int64) (int64, error) {
   
    result, err := db.Exec("DELETE FROM users WHERE id=?", id)
    if err != nil {
   
        return 0, err
    }
    rowsAffected, err := result.RowsAffected()
    if err != nil {
   
        return 0, err
    }
    return rowsAffected, nil
}

6. 使用命名参数来操作

// 使用命名参数插入用户
func insertUserNamed(db *sqlx.DB, name string, age int) (int64, error) {
   
    query := `INSERT INTO users(name, age) VALUES(:name, :age)`
    result, err := db.NamedExec(query, map[string]interface{
   }{
   
        "name": name,
        "age":  age,
    })
    if err != nil {
   
        return 0, err
    }
    id, err := result.LastInsertId()
    if err != nil {
   
        return 0, err
    }
    return id, nil
}

// 使用命名参数查询用户
func getUsersNamed(db *sqlx.DB, name string) ([]User, error) {
   
    query := `SELECT * FROM users WHERE name = :name`
    var users []User
    rows, err := db.NamedQuery(query, map[string]interface{
   }{
   
        "name": name,
    })
    if err != nil {
   
        return nil, err
    }
    defer rows.Close()
    for rows.Next() {
   
        var user User
        err := rows.StructScan(&user)
        if err != nil {
   
            fmt.Printf("scan failed, err:%v\n", err)
            continue
        }
        users = append(users, user)
    }

    return users, nil
}

7. 测试一下代码

func Run() {
   
    // 初始化数据库
    err := initDB()
    if err != nil {
   
        fmt.Printf("init DB failed, err:%v\n", err)
        return
    }
    defer db.Close() // 注意这行代码要写在上面err判断的下面

    // 创建表
    err = CreateTable(db)
    if err != nil {
   
        fmt.Printf("create table failed, err:%v\n", err)
        return
    }

    // 插入数据
    id, err := insertUser(db, "Alex", 18)
    if err != nil {
   
        fmt.Printf("insert user failed, err:%v\n", err)
        return
    }
    fmt.Println("insert success, the id is:", id)

    // 查询单条数据
    user, err := getUser(db, id)
    if err != nil {
   
        fmt.Printf("get user failed, err:%v\n", err)
        return
    }

    fmt.Printf("user:%#v\n", user)

    // 查询多条数据
    users, err := getAllUsers(db, 0)
    if err != nil {
   
        fmt.Printf("get all users failed, err:%v\n", err)
        return
    }

    fmt.Printf("users:%#v\n", users)

    // 更新数据
    rowsAffected, err := updateUser(db, id, "Alex", 20)
    if err != nil {
   
        fmt.Printf("update user failed, err:%v\n", err)
        return
    }

    fmt.Println("update success, affected rows:", rowsAffected)

    // 删除数据
    rowsAffected, err = deleteUser(db, id)
    if err != nil {
   
        fmt.Printf("delete user failed, err:%v\n", err)
        return
    }

    fmt.Println("delete success, affected rows:", rowsAffected)

    // 使用命名参数插入数据
    id, err = insertUserNamed(db, "Alex", 19)
    if err != nil {
   
        fmt.Printf("insert user named failed, err:%v\n", err)
        return
    }

    fmt.Println("insert named success, the id is:", id)

    // 使用命名参数查询数据
    users, err = getUsersNamed(db, "Alex")
    if err != nil {
   
        fmt.Printf("get users named failed, err:%v\n", err)
        return
    }

    fmt.Printf("users named:%#v\n", users)

    fmt.Println("exec SQL success")
}

我们可以看到,使用 sqlx 还是要比 database/sql 要简洁许多。

总结

通过 sqlx 包,我们可以更简单地在 Go 中与 MySQL 数据库进行交互,减少了样板代码并提高了代码的可读性。

希望这篇文章能帮助你更好地理解如何在 Go 中使用 sqlx 操作 MySQL 数据库!

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
7月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
7月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
1月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
1月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
2月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
2月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
238 0
|
3月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
4月前
|
分布式计算 Go C++
初探Go语言RPC编程手法
总的来说,Go语言的RPC编程是一种强大的工具,让分布式计算变得简单如同本地计算。如果你还没有试过,不妨挑战一下这个新的编程领域,你可能会发现新的世界。
110 10
|
7月前
|
存储 缓存 监控
企业监控软件中 Go 语言哈希表算法的应用研究与分析
在数字化时代,企业监控软件对企业的稳定运营至关重要。哈希表(散列表)作为高效的数据结构,广泛应用于企业监控中,如设备状态管理、数据分类和缓存机制。Go 语言中的 map 实现了哈希表,能快速处理海量监控数据,确保实时准确反映设备状态,提升系统性能,助力企业实现智能化管理。
120 3
|
7月前
|
存储 缓存 安全
Go 语言中的 Sync.Map 详解:并发安全的 Map 实现
`sync.Map` 是 Go 语言中用于并发安全操作的 Map 实现,适用于读多写少的场景。它通过两个底层 Map(`read` 和 `dirty`)实现读写分离,提供高效的读性能。主要方法包括 `Store`、`Load`、`Delete` 等。在大量写入时性能可能下降,需谨慎选择使用场景。

推荐镜像

更多