golang零样板代码数据库操作插件库dbq的使用

Golang零样板代码数据库操作插件库dbq的使用

简介

dbq是一个Golang数据库操作库,可以显著减少数据库操作的样板代码。它支持MySQL和PostgreSQL,提供便捷的开发者友好接口。

dbq logo

特性

  • 支持任何类型的查询
  • 兼容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库通过以下方式实现了零样板代码:

  1. 自动映射查询结果到结构体
  2. 简化CRUD操作
  3. 提供便捷的事务支持
  4. 支持批量操作
  5. 灵活的查询选项配置

相比直接使用database/sql,dbq可以显著减少重复代码,同时保持足够的灵活性。它特别适合中小型项目,可以快速实现数据库操作而无需引入复杂的ORM框架。

回到顶部