介绍
在 Go 语言中,标准库提供的 database/sql
包可以与各种数据库进行交互,但在某些情况下,使用更高层的库如 sqlx
可以使代码更加简洁和易于维护。sqlx
是一个扩展了 database/sql
的库,提供了更多便捷的功能,比如命名参数、结构体扫描等。本文将介绍如何使用 sqlx
与 MySQL 数据库进行基本的操作,包括连接数据库、执行查询、插入、更新和删除记录。
安装
go get github.com/jmoiron/sqlx
go get github.com/go-sql-driver/mysql
连接数据库
使用 sqlx
连接到 MySQL 数据库的代码示例如下:
package main
import (
"log"
"github.com/jmoiron/sqlx"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 数据库连接字符串
dsn := "username:password@tcp(localhost:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := sqlx.Connect("mysql", dsn)
if err != nil {
log.Fatalln(err)
}
defer db.Close()
log.Println("成功连接到数据库")
}
在连接字符串中,需要根据自己的 MySQL 配置替换 username
、password
和 dbname
。
基本的 CRUD 操作
1. 创建(Insert)
下面是使用 sqlx
插入数据的示例:
type User struct {
ID int64 `db:"id"` // 注意 db 标签
Name string `db:"name"`
Age int `db:"age"`
}
func createUser(db *sqlx.DB, name string, age int) (int64, error) {
query := "INSERT INTO users (name, age) VALUES (?, ?)"
result, err := db.Exec(query, name, age)
if err != nil {
return 0, err
}
id, err := result.LastInsertId()
return id, err
}
2. 读取(Select)
获取数据同样很简单,可以使用 Get
和 Select
方法。
获取单个用户信息:
func getUser(db *sqlx.DB, id int64) (*User, error) {
user := &User{}
query := "SELECT id, name, age FROM users WHERE id = ?"
err := db.Get(user, query, id)
if err != nil {
return nil, err
}
return user, nil
}
获取所有用户:
func getAllUsers(db *sqlx.DB) ([]User, error) {
var users []User
query := "SELECT id, name, age FROM users"
err := db.Select(&users, query)
return users, err
}
3. 更新(Update)
更新数据使用 Exec
方法:
func updateUser(db *sqlx.DB, id int64, name string, age int) error {
query := "UPDATE users SET name = ?, age = ? WHERE id = ?"
_, err := db.Exec(query, name, age, id)
return err
}
4. 删除(Delete)
func deleteUser(db *sqlx.DB, id int64) error {
query := "DELETE FROM users WHERE id = ?"
_, err := db.Exec(query, id)
return err
}
使用事务
在处理多个数据库操作时,使用事务可以确保数据的一致性。例如,可以在创建用户的同时记录日志:
func createUserWithTransaction(db *sqlx.DB, name string, age int) error {
tx := db.MustBegin()
// 插入用户
_, err := tx.Exec("INSERT INTO users (name, age) VALUES (?, ?)", name, age)
if err != nil {
tx.Rollback()
return err
}
// 记录日志(假设有一个日志表)
_, err = tx.Exec("INSERT INTO user_logs (user_name) VALUES (?)", name)
if err != nil {
tx.Rollback()
return err
}
return tx.Commit()
}
错误处理
if err == sql.ErrNoRows {
log.Println("没有找到用户")
} else if err != nil {
log.Fatal(err)
}
封装工具类CURD
import (
"core"
"fmt"
"log"
"strconv"
"strings"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
func InitClientMysql(auth core.Auth, dbname string) *sqlx.DB {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", auth.Name, auth.Pwd, auth.Host, 3306, dbname)
client, err := sqlx.Connect("mysql", dsn)
if err != nil {
log.Println(fmt.Sprintf("connect to %s %s failed", auth.Host, dbname))
log.Println(err)
}
client.SetMaxOpenConns(25)
client.SetMaxIdleConns(25)
client.SetConnMaxIdleTime(15 * time.Minute)
err = client.Ping()
log.Println(fmt.Sprintf("connect to %s %s successfully", auth.Host, dbname))
return client
}
func Insert(client *sqlx.DB, tablename string, param map[string]interface{}) int64 {
var keys []string
var values []string
for key, value := range param {
keys = append(keys, key)
switch value.(type) {
case int, int64, int32:
values = append(values, strconv.Itoa(value.(int)))
case string:
values = append(values, value.(string))
case float32, float64:
values = append(values, strconv.FormatFloat(value.(float64), 'f', -1, 64))
}
}
fileValue := "'" + strings.Join(values, "','") + "'"
fileds := "`" + strings.Join(keys, "`,`") + "`"
isql := fmt.Sprintf("INSERT INTO %v (%v) VALUES (%v)", tablename, fileds, fileValue)
log.Println(isql)
result, err := client.Exec(isql)
if err != nil {
log.Println(err)
}
s, err := result.LastInsertId()
log.Println(s)
return s
}
func Update(client *sqlx.DB, tablename string, where string, param map[string]interface{}) int {
var setValue []string
for key, value := range param {
switch value.(type) {
case int, int64, int32:
set := fmt.Sprintf("%v = %v", key, value.(int))
setValue = append(setValue, set)
case string:
set := fmt.Sprintf("%v = '%v'", key, value.(string))
setValue = append(setValue, set)
case float32, float64:
set := fmt.Sprintf("%v = '%v'", key, strconv.FormatFloat(value.(float64), 'f', -1, 64))
setValue = append(setValue, set)
}
}
setData := strings.Join(setValue, ",")
usql := fmt.Sprintf("UPDATE %v SET %v WHERE %v", tablename, setData, where)
log.Println(usql)
result, err := client.Exec(usql)
if err != nil {
log.Println(err)
}
s, _ := result.RowsAffected()
return int(s)
}
func Delete(client *sqlx.DB, tablename string, param string) int64 {
dsql := fmt.Sprintf("DELETE FROM %v WHERE %v", tablename, param)
log.Println(dsql)
result, err := client.Exec(dsql)
if err != nil {
log.Println(err)
}
s, _ := result.RowsAffected()
return s
}
func WaitNew(client *sqlx.DB, query string, wait int) {
var num int
log.Println(query)
for {
err := client.QueryRow(query).Scan(&num)
if err != nil {
log.Println(err)
}
log.Println(num)
if num > 0 {
log.Println(fmt.Sprintf("wait %d Second", wait*10))
time.Sleep(time.Duration(wait*10) * time.Second)
} else {
break
}
}
}