Go语言连接MySQL数据库:sqlx库实操指南

Luna
Luna
发布时间:2026-10-16 | 6人浏览过
原创

本文将详细介绍如何使用 Go 语言的 sqlx 库连接并操作 MySQL 数据库。内容包括依赖安装、连接池配置、常用查询方法(Query/Get/Select)以及事务处理,帮助开发者实现更高效的数据交互。

准备条件

第1步:安装依赖包

在使用 sqlx 之前,需要确保安装了基础的 database/sql 驱动以及 sqlx 扩展库。打开终端执行以下命令:

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

连接数据库

第2步:初始化数据库连接

使用 sqlx.Open 建立连接。不同于原生 sql.Open,建议显式检查连接状态并通过 Ping() 验证连通性。

package main
import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB  //全局对象db

func initDB() (err error) {
	db, err = sql.Open("mysql","root:admin123@tcp(127.0.0.1:3306)/dududu?charset=utf8")
	if err!=nil{
		return err
	}
	err = db.Ping()  //校验数据库连接
	if err!=nil{
		return err
	}
	return nil
}

func queryRowDemo()  {
	// 注意:实际使用中需传入指针 
	type User struct {
		SpuID   string
		Title   string
		Price   string
	}
	var u User
	sqlStr := "select spu_id,title,price from dududu_shops where id = ?"
	err:=db.QueryRow(sqlStr, 101).Scan(&u.SpuID,&u.Title,&u.Price)
	if err!=nil{
		fmt.Println("Error:", err)
	}
	fmt.Println(u)
}

func main()  {
	err:=initDB()
	if err!=nil{
		fmt.Println("Init Error:", err)
		return
	}
	queryRowDemo()
}

第3步:优化连接池设置

生产环境中应合理配置连接池参数以避免资源耗尽或连接数不足:

  • SetMaxOpenConns(n int):设置最大打开的连接数。
  • SetMaxIdleConns(n int):设置保留在连接池中的最大空闲连接数。

注:golang.org/x/net/context 相关的超时控制可能需要引入额外的包,此处仅展示基础池设置。

Db.SetMaxOpenConns(30)
Db.SetMaxIdleConns(15)

建表基础

下文所有 CRUD 示例均基于以下表结构进行操作:

CREATE TABLE `userinfo` (
    `uid` INT(10) NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(64) DEFAULT NULL,
    `password` VARCHAR(32) DEFAULT NULL,
    `department` VARCHAR(64) DEFAULT NULL,
    `email` varchar(64) DEFAULT NULL,
    PRIMARY KEY (`uid`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8

数据处理核心概念

sqlx 在原生 database/sql 基础上提供了更便捷的数据转换方式。主要包含以下几类 Handle Types 和 Cursor:

  • Handle Types:
    • sqlx.DB:表示数据库连接。
    • sqlx.Tx:表示事务。
    • sqlx.Stmt:预编译语句。
    • sqlx.NamedStmt:支持命名参数的预编译语句。
  • Cursor Types:
    • sqlx.Rows:用于遍历多行结果。
    • sqlx.Row:用于获取单行结果。
  • 新增功能:提供了 Get(dest interface{}, ...) 和 Select(dest interface{}, ...),可直接将查询结果映射到结构体切片或单个结构体中。

Exec 使用:增删改操作

第4步:执行插入、更新和删除

Exec 方法适用于不返回行的 SQL 操作(如 INSERT, UPDATE, DELETE)。注意 MySQL 占位符为 ?,不同数据库可能不同(如 Oracle 使用 :name)。

package main
import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
    "fmt"
)
var Db *sqlx.DB

func init()  {
    var db *sqlx.DB
    var err error
    db, err = sqlx.Open("mysql", "stu:1234qwer@tcp(10.0.0.241:3307)/test?charset=utf8")
    if err != nil {
        fmt.Println("open mysql failed,", err)
        return
    }
    Db = db
}

func main()  {
    // 插入
    result, err := Db.Exec("INSERT INTO userinfo (username, password, department,email) VALUES (?, ?, ?,?)",
        "wd","123","it","wd@163.com")
    if err != nil{
        fmt.Println("insert failed,error: ", err)
        return
    }
    id,_ := result.LastInsertId()
    fmt.Println("insert id is :",id)

    // 更新
    _, err1 := Db.Exec("update userinfo set username = ? where uid = ?","jack",1)
    if err1 != nil{
        fmt.Println("update failed error:",err1)
    } else {
        fmt.Println("update success!")
    }

    // 删除
    _, err2 := Db.Exec("delete from userinfo where uid = ? ", 1)
    if err2 != nil{
        fmt.Println("delete error:",err2)
    }else{
        fmt.Println("delete success")
    }
}

预声明语句(Prepared Statements)

预编译语句可以提升重复执行的效率,并防止 SQL 注入。

原生 Prepare 用法:

stmt, err := db.Prepare(`SELECT * FROM place WHERE telcode=?`)
row = stmt.QueryRow(65)

sqlx 扩展了 Preparex,可直接关联结构体:

stmt, err := db.Preparex(`SELECT * FROM place WHERE telcode=?`)
var p Place
err = stmt.Get(&p, 852)

Query 系列:读取数据

第5步:传统扫描 Row Scan

Query 返回 *sql.Rows 对象,需手动迭代并使用 Scan 赋值给变量。务必在循环结束后检查错误,并确保 rows.Close() 被调用以释放连接。

rows, err := Db.Query("SELECT username,password,email FROM userinfo")
if err != nil{
    fmt.Println("query failed,", err)
    return
}
defer rows.Close()
for rows.Next() {
    var username,password,email string
    err = rows.Scan(&username, &password, &email)
    if err != nil { panic(err) }
    println(username,password,email)
}

第6步:使用 StructScan 简化读取

Queryx 配合 StructScan 可将一行数据直接转换为结构体字段,前提是结构体标签需指定列名(如 `db:"username"`)。

type stu struct {
    Username string   `db:"username"`
    Password string      `db:"password"`
    Department string  `db:"department"`
    Email string        `db:"email"`
}

rows, err := Db.Queryx("SELECT username,password,email FROM userinfo")
for rows.Next() {
    var s stu
    err = rows.StructScan(&s)
    fmt.Println(s.Username)
}

第7步:获取单行 Get/QueryRow

QueryRow 返回 *sql.Row,如果查询结果为空会返回 sql.ErrNoRows。

var s stu
// QueryRowx 可直接绑定到结构体
err1 := Db.QueryRowx("SELECT username,password,email FROM userinfo where uid = ?",2).StructScan(&s)
if err1 != nil{
    fmt.Println("Error :",err1)
}else {
    fmt.Printf("Result:%v\n",s)
}

第8步:批量查询 Select

Get 用于单次结果映射,Select 用于多条记录映射到切片,这是最常用的两种模式。

var stus []stu
// 获取所有记录
err := Db.Select(&stus,"SELECT username,password,email FROM userinfo")
if err != nil{
    fmt.Println("Select error",err)
}
fmt.Printf("All users: %v\n",stus)

var s stu
// 获取单条记录
err1 := Db.Get(&s,"SELECT username,password,email FROM userinfo where uid = ?",2)
if err1 != nil{
    fmt.Println("GET error :",err1)
}else {
    fmt.Printf("Single user: %v\n",s)
}

事务(Transactions)

事务操作保证了一组操作的原子性,要么全部成功,要么全部回滚。关键步骤包括 Begin、Exec、Commit 和 Rollback。

tx, err := Db.Beginx()
// 第一笔操作
_, err = tx.Exec("insert into userinfo(username,password) values(?,?)", "Rose","2223")
if err != nil {
    tx.Rollback() // 出错立即回滚
    fmt.Println("exec sql error:", err)
    return
}
// 第二笔操作
_, err = tx.Exec("insert into userinfo(username,password) values(?,?)", "Mick",222)
if err != nil {
    tx.Rollback()
    fmt.Println("exec sql error:", err)
    return
}
// 提交事务
err = tx.Commit()
if err != nil {
    fmt.Println("commit error")
}

注意:Tx 对象持有单一连接,因此必须尽快 Commit 或 Rollback 以释放资源,避免连接池泄漏。

完整案例演示

以下是一个结合初始化与基本查询的整合示例:

var Db *sqlx.DB
db, err := sqlx.Open("mysql","root:admin123@tcp(127.0.0.1:3306)/dududu?charset=utf8")
Db = db

rows, err := Db.Query("SELECT spu_id,title,price FROM dududu_shops")
if err != nil{
  fmt.Println("query failed,", err)
  return
}
defer rows.Close()
for rows.Next() {
  var spu_id,title,price string
  err = rows.Scan(&spu_id, &title, &price)
  if err != nil { panic(err) }
  println(spu_id,title,price)
}

以上就是 Go 语言利用 sqlx 库连接并操作 MySQL 数据库的详细内容,更多关于 Golang 操作数据库的实践技巧请持续关注本站后续文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表