golang零样板代码数据库操作插件库dbq的使用
Golang零样板代码数据库操作插件库dbq的使用
简介
dbq是一个Golang数据库操作库,可以显著减少数据库操作的样板代码。它支持MySQL和PostgreSQL,提供便捷的开发者友好接口。
特性
- 支持任何类型的查询
- 兼容MySQL和PostgreSQL
- 便捷且开发者友好
- 接受任何类型的切片作为查询参数
- 自动将查询参数切片展平为单个值
- 无缝批量插入
- 使用mapstructure包自动将查询结果直接解组到结构体
- 轻量级
- 兼容mysql-go以正确取消MySQL查询
- 操作失败时自动使用指数退避重试查询
- 事务管理(自动回滚)
安装
go get -u github.com/rocketlaunchr/dbq/v2
示例
假设有一个名为users
的表:
id | name | age | created_at |
---|---|---|---|
1 | Sally | 12 | 2019-03-01 |
2 | Peter | 15 | 2019-02-01 |
3 | Tom | 18 | 2019-01-01 |
查询
type user struct {
ID int `dbq:"id"`
Name string `dbq:"name"`
Age int `dbq:"age"`
CreatedAt time.Time `dbq:"created_at"`
}
opts := &dbq.Options{ConcreteStruct: user{}, DecoderConfig:x}
results, err := dbq.Q(ctx, db, "SELECT * FROM users", opts)
results, err := dbq.Qs(ctx, db, "SELECT * FROM users", user{}, nil)
查询单行
result := dbq.MustQ(ctx, db, "SELECT * FROM users LIMIT 1", dbq.SingleResult)
if result == nil {
// 无结果
} else {
result.(map[string]interface{})
}
批量插入
db, _ := sql.Open("mysql", "user:password@tcp(localhost:3306)/db")
type Row struct {
Name string
Age int
CreatedAt time.Time
}
users := []interface{}{
dbq.Struct(Row{"Brad", 45, time.Now()}),
dbq.Struct(Row{"Ange", 36, time.Now()}),
dbq.Struct(Row{"Emily", 22, time.Now()}),
}
stmt := dbq.INSERTStmt("users", []string{"name", "age", "created_at"}, len(users))
dbq.E(ctx, db, stmt, nil, users)
展平查询参数
args1 := []string{"A", "B", "C"}
args2 := []interface{}{2, "D"}
args3 := dbq.Struct(Row{"Brad Pitt", 45, time.Now()})
results := dbq.MustQ(ctx, db, stmt, args1, args2, args3)
// 占位符参数将被展平为:
results := dbq.MustQ(ctx, db, stmt, "A", "B", "C", 2, "D", "Brad Pitt", 45, time.Now())
MySQL取消
import sql "github.com/rocketlaunchr/mysql-go"
pool, _ := sql.Open("user:password@tcp(localhost:3306)/db")
conn, err := pool.Conn(ctx)
opts := &dbq.Options{
SingleResult: true,
PostFetch: func(ctx context.Context) error {
return conn.Close()
},
}
result := dbq.MustQ(ctx, conn, "SELECT * FROM users LIMIT 1", opts)
if result == nil {
// 无结果
} else {
result.(map[string]interface{})
}
事务管理
ctx := context.Background()
pool, _ := sql.Open("mysql", "user:password@tcp(localhost:3306)/db")
dbq.Tx(ctx, pool, func(tx interface{}, Q dbq.QFn, E dbq.EFn, txCommit dbq.TxCommit) {
stmt := dbq.INSERTStmt("table", []string{"name", "age", "created_at"}, 1)
res, err := E(ctx, stmt, nil, "test name", 34, time.Now())
if err != nil {
return // 自动回滚
}
txCommit() // 提交
})
完整示例
package main
import (
"context"
"database/sql"
"fmt"
"time"
"github.com/rocketlaunchr/dbq/v2"
_ "github.com/go-sql-driver/mysql"
)
type User struct {
ID int `dbq:"id"`
Name string `dbq:"name"`
Age int `dbq:"age"`
CreatedAt time.Time `dbq:"created_at"`
}
func main() {
// 1. 连接数据库
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
ctx := context.Background()
// 2. 查询所有用户
opts := &dbq.Options{ConcreteStruct: User{}}
users, err := dbq.Q(ctx, db, "SELECT * FROM users", opts)
if err != nil {
panic(err)
}
fmt.Printf("查询结果: %+v\n", users.([]*User))
// 3. 批量插入用户
newUsers := []interface{}{
dbq.Struct(User{Name: "Alice", Age: 25, CreatedAt: time.Now()}),
dbq.Struct(User{Name: "Bob", Age: 30, CreatedAt: time.Now()}),
}
stmt := dbq.INSERTStmt("users", []string{"name", "age", "created_at"}, len(newUsers))
_, err = dbq.E(ctx, db, stmt, nil, newUsers)
if err != nil {
panic(err)
}
fmt.Println("批量插入成功")
// 4. 使用事务
dbq.Tx(ctx, db, func(tx interface{}, Q dbq.QFn, E dbq.EFn, txCommit dbq.TxCommit) {
// 在事务中更新用户年龄
_, err := E(ctx, "UPDATE users SET age = ? WHERE name = ?", nil, 26, "Alice")
if err != nil {
fmt.Println("事务出错:", err)
return // 自动回滚
}
// 提交事务
txCommit()
fmt.Println("事务提交成功")
})
}
这个示例展示了dbq的主要功能,包括查询、批量插入和事务管理。dbq可以显著减少数据库操作的样板代码,使代码更加简洁易读。
更多关于golang零样板代码数据库操作插件库dbq的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang零样板代码数据库操作插件库dbq的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang零样板数据库操作插件库dbq使用指南
dbq是一个轻量级的Golang数据库操作库,旨在消除样板代码,提供简洁高效的数据库访问方式。下面我将详细介绍dbq的使用方法。
安装
go get github.com/rocketlaunchr/dbq/v2
基本用法
1. 初始化连接
import (
"database/sql"
"github.com/rocketlaunchr/dbq/v2"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 创建标准database/sql连接
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
defer db.Close()
// 将连接传递给dbq
dbq.SetDb(db)
}
2. 查询单条记录
type User struct {
ID int `dbq:"id"`
Username string `dbq:"username"`
Email string `dbq:"email"`
}
// 查询单条记录
func getUser(id int) (*User, error) {
query := "SELECT id, username, email FROM users WHERE id = ?"
opts := &dbq.Options{ConcreteStruct: User{}, SingleResult: true}
result, err := dbq.Q(context.TODO(), dbq.DB(), query, opts, id)
if err != nil {
return nil, err
}
return result.(*User), nil
}
3. 查询多条记录
// 查询多条记录
func getAllUsers() ([]*User, error) {
query := "SELECT id, username, email FROM users"
opts := &dbq.Options{ConcreteStruct: User{}}
result, err := dbq.Q(context.TODO(), dbq.DB(), query, opts)
if err != nil {
return nil, err
}
return result.([]*User), nil
}
4. 插入数据
// 插入数据
func createUser(user *User) (int64, error) {
stmt := dbq.INSERTStmt("users", []string{"username", "email"}, 1, dbq.MySQL)
res, err := dbq.E(context.TODO(), dbq.DB(), stmt, nil, user.Username, user.Email)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
5. 批量插入
// 批量插入
func batchInsertUsers(users []*User) (int64, error) {
// 准备数据
data := make([]interface{}, len(users))
for i, u := range users {
data[i] = []interface{}{u.Username, u.Email}
}
stmt := dbq.INSERTStmt("users", []string{"username", "email"}, len(users), dbq.MySQL)
res, err := dbq.E(context.TODO(), dbq.DB(), stmt, nil, data...)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
6. 更新数据
// 更新数据
func updateUser(user *User) (int64, error) {
stmt := "UPDATE users SET username = ?, email = ? WHERE id = ?"
res, err := dbq.E(context.TODO(), dbq.DB(), stmt, nil, user.Username, user.Email, user.ID)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
7. 事务处理
func transferMoney(fromID, toID int, amount float64) error {
tx, err := dbq.DB().BeginTx(context.TODO(), nil)
if err != nil {
return err
}
defer func() {
if err != nil {
tx.Rollback()
}
}()
// 扣款
_, err = dbq.E(context.TODO(), tx, "UPDATE accounts SET balance = balance - ? WHERE id = ?", nil, amount, fromID)
if err != nil {
return err
}
// 存款
_, err = dbq.E(context.TODO(), tx, "UPDATE accounts SET balance = balance + ? WHERE id = ?", nil, amount, toID)
if err != nil {
return err
}
return tx.Commit()
}
高级特性
1. 自定义映射
type CustomUser struct {
UserID int `dbq:"id"`
Name string `dbq:"username"`
Mail string `dbq:"email"`
}
func getCustomUser(id int) (*CustomUser, error) {
query := "SELECT id, username, email FROM users WHERE id = ?"
opts := &dbq.Options{
ConcreteStruct: CustomUser{},
SingleResult: true,
DecoderConfig: dbq.StdTimeConversionConfig(),
}
result, err := dbq.Q(context.TODO(), dbq.DB(), query, opts, id)
if err != nil {
return nil, err
}
return result.(*CustomUser), nil
}
2. 使用原生SQL结果
func getRawResults() ([]map[string]interface{}, error) {
query := "SELECT id, username, email FROM users"
opts := &dbq.Options{
RawResults: true,
}
result, err := dbq.Q(context.TODO(), dbq.DB(), query, opts)
if err != nil {
return nil, err
}
return result.([]map[string]interface{}), nil
}
3. 连接池配置
func initDB() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {
panic(err)
}
// 配置连接池
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(25)
db.SetConnMaxLifetime(5 * time.Minute)
dbq.SetDb(db)
}
总结
dbq库通过以下方式实现了零样板代码:
- 自动映射查询结果到结构体
- 简化CRUD操作
- 提供便捷的事务支持
- 支持批量操作
- 灵活的查询选项配置
相比直接使用database/sql,dbq可以显著减少重复代码,同时保持足够的灵活性。它特别适合中小型项目,可以快速实现数据库操作而无需引入复杂的ORM框架。