dbx

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 3 Imported by: 0

README

dbx

dbx 是一个 Go 语言数据库工具库,在标准库 database/sql 之上提供了两层能力:

  • SQL 映射层(sqlx 风格):结构体扫描、命名查询、绑定变量适配。
  • 轻量 ORM 层:基于结构体标签的 CRUD、链式查询构建器、生命周期钩子、软删除。

保持「SQL 优先、反射映射、低侵入」的设计:ORM 只生成常见的 CRUD SQL 与结构化查询, 复杂查询仍可直接书写 SQL。

特性

  • 结构体 ↔ 表/列的自动映射(snake_case 命名、嵌入结构体展开、db 标签)
  • 多数据库绑定变量适配(? / $1 / :name / @p1
  • 命名查询(Named Query)与 In 切片展开,支持批量插入(VALUES 多行展开)
  • Context 支持、事务 Tx、预编译 StmtDB/Tx 通过 Queryable 接口无缝切换
  • 反射映射结果缓存(Mapper 类型级缓存 + 循环扫描跨行复用)
  • ORM:Create / Save / Updates / Delete / Find / First / Take / Count / Pluck
  • 链式查询:Where / Or / OrderBy / Group / Having / Joins / Limit / Offset
  • 生命周期钩子(接口 + 注册表)
  • 软删除(Unscoped 关闭过滤)
  • 自增主键回填、autoCreateTime / autoUpdateTime 自动填充
  • Unsafe 模式:结果集列在目标结构体缺失时静默扫描
  • LoadFile 执行 SQL 脚本文件
  • 内置实现 sql.Scanner / driver.Valuer 的自定义类型(JSON、BitBool、Gzip、时间等)
  • 可插拔 SQL 日志:通过 Logger 接口适配任意日志库,用 LogProd / LogDebug 区分生产与开发环境

安装

go get gitee.com/bytools/dbx

要求 Go 1.26 及以上。

快速开始

连接数据库
import "gitee.com/bytools/dbx"

db, err := dbx.Connect("mysql", "user:pass@tcp(127.0.0.1:3306)/test?parseTime=true")
if err != nil {
    panic(err)
}
defer db.Close()

// 或使用 MustOpen / MustConnect(出错时 panic)
db := dbx.MustOpen("postgres", "postgres://user:pass@localhost/test?sslmode=disable")
SQL 查询(sqlx 风格)
type User struct {
    ID   int64  `db:"id"`
    Name string `db:"name"`
    Age  int    `db:"age"`
}

// 查询多条
var users []User
err := db.Select(&users, "SELECT * FROM users WHERE age > ?", 18)

// 查询单条
var user User
err := db.Get(&user, "SELECT * FROM users WHERE id = ?", 1)

// 执行写操作
res, err := db.Exec("UPDATE users SET age = ? WHERE id = ?", 20, 1)
命名查询
// 使用 map 参数
rows, err := db.NamedQuery("SELECT * FROM users WHERE name = :name", map[string]any{"name": "tom"})

// 使用结构体参数
_, err = db.NamedExec("INSERT INTO users (name, age) VALUES (:name, :age)", &User{Name: "tom", Age: 18})

// In 切片展开
query, args, _ := dbx.In("SELECT * FROM users WHERE id IN (?)", []int{1, 2, 3})
err = db.Select(&users, query, args...)
事务与 DB/Tx 无缝切换

*dbx.DB*dbx.Tx 都实现了 Queryable 接口,业务函数声明为该接口类型即可在连接与事务之间无缝复用:

// 开始事务:Beginx 返回 *dbx.Tx,用法与 *dbx.DB 一致
tx, err := db.Beginx()
if err != nil {
    panic(err)
}
defer tx.Rollback()

if err := tx.Select(&users, "SELECT * FROM users WHERE age > ?", 18); err != nil {
    panic(err)
}
if _, err := tx.Exec("UPDATE users SET age = age + 1 WHERE id = ?", 1); err != nil {
    panic(err)
}
if err := tx.Commit(); err != nil {
    panic(err)
}

// 业务函数接受 dbx.Queryable,从而同时接收 *dbx.DB 与 *dbx.Tx
func listUsers(q dbx.Queryable, age int) ([]User, error) {
    var users []User
    err := q.Select(&users, "SELECT * FROM users WHERE age > ?", age)
    return users, err
}
Context 支持

查询与执行方法均提供对应的 ...Context 版本,事务也可通过 BeginTxx 传入 context

ctx := context.Background() // 需 import "context"

if err := db.SelectContext(ctx, &users, "SELECT * FROM users WHERE age > ?", 18); err != nil {
    panic(err)
}
if err := db.GetContext(ctx, &user, "SELECT * FROM users WHERE id = ?", 1); err != nil {
    panic(err)
}
if _, err := db.ExecContext(ctx, "UPDATE users SET age = ? WHERE id = ?", 20, 1); err != nil {
    panic(err)
}
tx, err := db.BeginTxx(ctx, nil)
ORM 层

定义模型,通过 db 标签描述映射与语义:

type User struct {
    ID        int64      `db:"id,primarykey,autoincrement"`
    Name      string     `db:"name"`
    Age       int        `db:"age,omitempty"`
    Email     string     `db:"-"`
    CreatedAt time.Time  `db:"created_at,autoCreateTime"`
    UpdatedAt time.Time  `db:"updated_at,autoUpdateTime"`
    DeletedAt *time.Time `db:"deleted_at,softdelete"`
}

// 可选:覆盖默认表名
func (User) TableName() string { return "t_user" }
CRUD
// 插入,自动填充时间并回填自增主键
err := dbx.Create(db, &user)

// 主键为零值则插入,否则更新
err = dbx.Save(db, &user)

// 更新指定列
err = dbx.Updates(db, &user, "name", "age")

// 删除(带 softdelete 字段时软删除)
err = dbx.Delete(db, &user)
查询
var users []User

// 链式查询
err := dbx.NewQuery(db).Model(&User{}).
    Where("age > ?", 18).
    Where("name = ?", "tom").
    OrderBy("id DESC").
    Limit(10).Offset(0).
    Find(&users)

Where / Or 支持字符串、map[string]any 与结构体(结构体非零字段生成等值条件)。

// 便捷函数
var user User
err = dbx.First(db, &user, "id = ?", 1) // 无记录返回 dbx.ErrRecordNotFound

var count int64
err = dbx.Count(db, &count, &User{}, "age > ?", 18)

// 查询单列
var names []string
err = dbx.Pluck(db, &names, "name", &User{}, "age > ?", 18)

// 查询任意一条记录
err = dbx.Take(db, &user)

// 含已删除数据 / 硬删除
err = dbx.NewQuery(db).Unscoped().Model(&User{}).Find(&users)
err = dbx.NewQuery(db).Unscoped().Delete(&user)
生命周期钩子

模型实现对应接口即可自动触发:

func (u *User) BeforeCreate() error { return nil }
func (u *User) AfterCreate() error  { return nil }
// BeforeUpdate / AfterUpdate / BeforeDelete / AfterDelete / AfterFind

也可通过注册表注册全局钩子:

s := dbx.NewQuery(db)
s.RegisterHook("before_create", func(model any) error { return nil })

结构体标签

沿用 db 标签,逗号分隔 name,option=value

标签 说明
db:"-" 忽略该字段
db:"col_name" 显式列名
db:"id,primarykey" 主键
db:"id,primarykey,autoincrement" 自增主键(创建时不写入、用于回填)
db:"created_at,autoCreateTime" 创建时自动写当前时间
db:"updated_at,autoUpdateTime" 创建/更新时自动写当前时间
db:",omitempty" 零值字段在 Insert/Update 中省略
db:"deleted_at,softdelete" 软删除标记
db:",column=xxx" 显式列名(等价于 db:"xxx"

SQL 日志

dbx 本身不依赖任何第三方日志库,而是提供一个 Logger 接口,由使用方实现以适配自身日志体系。通过 LogMode 区分生产环境与开发/测试环境:

  • dbx.LogProd(默认):不调用日志方法,直接执行,零额外开销。
  • dbx.LogDebug:记录 SQL 执行日志。
import (
    "go.uber.org/zap"

    "gitee.com/bytools/dbx"
)

// 实现 dbx.Logger 接口,适配自己的日志库
type zapLogger struct {
    log *zap.Logger
}

func (z zapLogger) LogSQL(e dbx.LogEntry) {
    fields := []zap.Field{
        zap.String("op", e.Operation),
        zap.String("query", e.Query),
        zap.Any("args", e.Args),
        zap.Duration("duration", e.Duration),
        zap.Int64("rows_affected", e.RowsAffected),
    }
    if e.Err != nil {
        fields = append(fields, zap.Error(e.Err))
    }
    z.log.Info("sql", fields...)
}

// 初始化时按环境接入
logger, _ := zap.NewDevelopment()
defer logger.Sync()

dbx.SetLogger(zapLogger{log: logger})
dbx.SetLogMode(dbx.LogDebug) // 生产环境改为 dbx.LogProd

LogEntry 字段:

字段 类型 说明
Operation string 操作类型:Exec / Query / QueryRow
Query string 执行的 SQL
Args []any 绑定参数
Duration time.Duration 执行耗时
Err error 错误(nil 表示成功)
RowsAffected int64 影响行数(查询时为 -1

全局函数:

  • dbx.SetLogger(l Logger):设置全局日志器,传 nil 关闭日志。
  • dbx.SetLogMode(m LogMode):设置全局日志模式。
  • dbx.GetLogger() / dbx.GetLogMode():读取当前配置。

在 debug 模式下,DB / Tx / ConnExec / Query / QueryRow 及其 ...Context 方法,以及 Select / Get / MustExec / NamedQuery / NamedExec 等上层方法都会记录日志;prod 模式下直接执行、不产生日志。

支持的驱动与绑定变量

绑定类型 占位符 常见驱动
QUESTION ? mysql、sqlite3
DOLLAR $1 postgres、pgx、cockroach
NAMED :name oracle
AT @p1 sqlserver

如需自定义驱动映射:

dbx.BindDriver("my-driver", dbx.DOLLAR)

包结构

dbx
├── core/        领域层:接口、Row/Rows、扫描/查询函数、绑定工具、日志接口
├── db/          基础设施层:DB/Tx/Stmt/Conn、命名查询、Context 支持、SQL 日志拦截
├── reflectx/    反射增强:字段映射(db 标签、嵌入结构体)
├── types/       内置类型:JSONText、BitBool、GzippedText、DBDate/DBDateTime/DBTime
├── orm/         ORM 层:模型元数据、CRUD、链式查询、钩子、软删除
└── cmd/server/  示例:接入 Uber Zap 打印 SQL 日志

顶层 dbx 包统一重导出以上能力。

License

MIT

Documentation

Overview

dbx 基于 sqlx 源码进行修改,是一个 Go 语言数据库工具库 在 `database/sql` 之上提供了 SQL 映射功能以及轻量的 ORM 功能 对比 sqlx, 提供了日志接入功能以及基于 vinovest/sqlx 的部分扩展功能进一步优化 接入了 sqltoken 包,用于解析 SQL 语句中的参数和函数调用 提供 `Row.Scan` 多行结果检测 LEFT JOIN 支持 LEFT JOIN 操作 重复列名按位置映射 列名映射函数 函数式选项 Queryable 接口统一 DB/TX 操作 多结果集支持 In 的 nil Valuer 处理以及 IN(...) 语义检测

Index

Constants

View Source
const (
	UNKNOWN  = core.UNKNOWN  // 未知绑定类型
	QUESTION = core.QUESTION // 问号绑定类型 ?
	DOLLAR   = core.DOLLAR   // 美元符号绑定类型 $
	NAMED    = core.NAMED    // 命名参数绑定类型 :name
	AT       = core.AT       // @ 符号绑定类型 @name
)
View Source
const (
	LogProd  = core.LogProd  // LogProd 生产模式:不调用日志方法
	LogDebug = core.LogDebug // LogDebug 调试模式:调用日志方法打印 SQL
)

Variables

View Source
var (
	BindType   = core.BindType   // BindType 根据驱动程序名称返回数据库绑定类型
	BindDriver = core.BindDriver // BindDriver 将 driverName 的 BindType 设置为 bindType
	Rebind     = core.Rebind     // Rebind 将查询默认绑定类型(QUESTION)重新绑定到目标绑定类型
	RebindBuff = core.RebindBuff // RebindBuff 是 Rebind 的实验性实现,使用 bytes.Buffer,代码更简单但速度较慢
	In         = core.In         // In 展开 args 中的切片值,返回修改后的查询字符串和新的参数列表
)
View Source
var (
	Select     = core.Select     // Select 使用提供的 Queryer 执行查询,并将每行通过 StructScan 扫描到 dest 中
	Get        = core.Get        // Get 使用提供的 Queryer 执行 QueryRow,并将结果行扫描到 dest 中
	MustExec   = core.MustExec   // MustExec 使用 e 执行查询,如果发生错误则 panic
	StructScan = core.StructScan // StructScan 将所有行扫描到 dest 切片中
	SliceScan  = core.SliceScan  // SliceScan 扫描一行,返回类似 MapScan 的 []any 值
	MapScan    = core.MapScan    // MapScan 将单行扫描到 dest map[string]any 中
	ScanAll    = core.ScanAll    // ScanAll 将所有行扫描到目标切片中
)
View Source
var (
	IsScannable       = core.IsScannable       // IsScannable 根据 reflect.Type 来判断目标是否可扫描
	Mapper            = core.Mapper            // Mapper 返回使用已配置 NameMapper 函数的有效 Mapper
	FieldsByTraversal = core.FieldsByTraversal // FieldsByTraversal 根据 traversals 中的路径,用传递的 value 的字段填充 values 接口切片
)
View Source
var (
	SetLogger  = core.SetLogger  // SetLogger 设置全局默认日志器,传入 nil 表示关闭日志
	SetLogMode = core.SetLogMode // SetLogMode 设置全局默认日志模式
	GetLogger  = core.GetLogger  // GetLogger 返回全局默认日志器(可能为 nil)
	GetLogMode = core.GetLogMode // GetLogMode 返回全局默认日志模式
)
View Source
var (
	Connect     = db.Connect     // Connect 连接到数据库并通过 ping 验证连接
	MustConnect = db.MustConnect // MustConnect 连接到数据库并在出错时 panic
	Open        = db.Open        // Open 与 sql.Open 相同,但返回 *dbx.DB
	MustOpen    = db.MustOpen    // MustOpen 与 sql.Open 相同,但返回 *dbx.DB 并在出错时 panic
	NewDb       = db.NewDb       // NewDb 为已存在的 *sql.DB 返回一个新的 dbx DB 封装
	Preparex    = db.Preparex    // Preparex 预编译一条语句
	LoadFile    = db.LoadFile    // LoadFile 执行文件中的每条语句
)
View Source
var (
	WithUnsafe    = db.WithUnsafe    // WithUnsafe 返回使构建出的类型处于不安全模式的选项
	WithSetUnsafe = db.WithSetUnsafe // WithSetUnsafe 返回设置不安全模式的选项
)
View Source
var (
	Named             = db.Named             // Named 接受使用命名参数的查询和一个参数,返回一个带有参数列表的新查询
	NamedQuery        = db.NamedQuery        // NamedQuery 绑定命名查询并运行 Query
	NamedExec         = db.NamedExec         // NamedExec 使用 BindStruct 获取可执行的查询并运行 Exec
	BindNamed         = db.BindNamed         // BindNamed 将结构体或 map 绑定到带有命名参数的查询
	BindNamedMapper   = db.BindNamedMapper   // BindNamedMapper 使用指定的 Mapper 进行命名绑定
	BindStruct        = db.BindStruct        // BindStruct 将命名参数查询与结构体参数的字段绑定
	BindMap           = db.BindMap           // BindMap 将命名参数查询与参数 map 绑定
	BindArray         = db.BindArray         // BindArray 将命名参数查询与结构体数组或切片参数的字段绑定
	CompileNamedQuery = db.CompileNamedQuery // CompileNamedQuery 将命名查询编译为未绑定的查询和名称列表
	FixBound          = db.FixBound          // FixBound 修复多行插入时的 VALUES 占位符
)
View Source
var (
	IsUnsafe  = db.IsUnsafe  // IsUnsafe 判断扩展类型是否处于不安全模式
	MapperFor = db.MapperFor // MapperFor 返回与给定接口关联的 Mapper
)
View Source
var (
	ConnectContext    = db.ConnectContext    // ConnectContext 连接到数据库并通过 ping 验证连接
	SelectContext     = db.SelectContext     // SelectContext 使用提供的 Queryer 执行查询,并将每行扫描到 dest 中
	GetContext        = db.GetContext        // GetContext 使用提供的 Queryer 执行 QueryRow,并将结果行扫描到 dest 中
	MustExecContext   = db.MustExecContext   // MustExecContext 使用 e 执行查询,如果发生错误则 panic
	LoadFileContext   = db.LoadFileContext   // LoadFileContext 执行文件中的每条语句
	PreparexContext   = db.PreparexContext   // PreparexContext 预编译一条语句
	NamedQueryContext = db.NamedQueryContext // NamedQueryContext 绑定命名查询并运行 Query
	NamedExecContext  = db.NamedExecContext  // NamedExecContext 使用 BindStruct 获取可执行的查询并运行 Exec
)
View Source
var (
	NewQuery = orm.NewQuery // NewQuery 基于底层执行器创建 Session。执行器可以是 *db.DB 或 *db.Tx
	Create   = orm.Create   // Create 插入一条记录
	Save     = orm.Save     // Save 主键为零值时插入,否则更新
	Updates  = orm.Updates  // Updates 按主键更新指定列(cols 为空时更新所有非主键/非自增列)
	Delete   = orm.Delete   // Delete 删除记录(带 softdelete 字段时软删除,除非 Unscoped)
	Find     = orm.Find     // Find 查询多条记录
	First    = orm.First    // First 查询首条记录
	Take     = orm.Take     // Take 查询任意一条记录
	Count    = orm.Count    // Count 统计记录数
	Pluck    = orm.Pluck    // Pluck 查询单列
)
View Source
var ErrMultiRows = core.ErrMultiRows

ErrMultiRows 在预期只返回单行的函数(如 Get)实际返回多行时返回。

View Source
var ErrRecordNotFound = orm.ErrRecordNotFound

-- ORM 错误 --

View Source
var NameMapper = core.NameMapper

NameMapper 用于将列名映射到结构体字段名。默认使用 strings.ToLower 将字段名转为小写。

Functions

This section is empty.

Types

type Binder

type Binder = core.Binder // Binder 是能够绑定查询的接口

type ColScanner

type ColScanner = core.ColScanner // ColScanner 是 MapScan 和 SliceScan 使用的接口

type Conn

type Conn = db.Conn // Conn 是 sql.Conn 的封装,提供额外的功能

type DB

type DB = db.DB // DB 是 sql.DB 的封装,在 Open 时记录 driverName,用于自动绑定命名查询

type DefaultNamer

type DefaultNamer = orm.DefaultNamer

type Execer

type Execer = core.Execer // Execer 是 MustExec 和 LoadFile 使用的接口

type ExecerContext

type ExecerContext = db.ExecerContext // ExecerContext 是带 Context 的执行接口

type Ext

type Ext = core.Ext // Ext 是一个联合接口,可以绑定、查询和执行

type ExtContext

type ExtContext = db.ExtContext // ExtContext 是带 Context 的联合接口,可以绑定、查询和执行

type Field

type Field = orm.Field

type LogEntry

type LogEntry = core.LogEntry // LogEntry 描述一次 SQL 执行

type LogMode

type LogMode = core.LogMode // LogMode 定义 SQL 日志的启用模式

type Logger

type Logger = core.Logger // Logger 是 SQL 日志接口,由使用方实现以适配自身日志库

type NamedStmt

type NamedStmt = db.NamedStmt // NamedStmt 是一个执行命名查询的预编译语句

type Namer

type Namer = orm.Namer

type Preparer

type Preparer = core.Preparer // Preparer 是 Preparex 使用的接口

type PreparerContext

type PreparerContext = db.PreparerContext // PreparerContext 是带 Context 的预编译接口

type QStmt

type QStmt = db.QStmt // QStmt 是一个封装,通过实现 Queryer 和 Execer 接口使 Stmt 可复用

type Query

type Query = orm.Query

type Queryable

type Queryable = db.Queryable // Queryable 是统一 DB 与 Tx 的联合接口,二者可互换使用

type Queryer

type Queryer = core.Queryer // Queryer 是 Get 和 Select 使用的接口

type QueryerContext

type QueryerContext = db.QueryerContext // QueryerContext 是带 Context 的查询接口

type Row

type Row = core.Row // Row 是对 sql.Row 的重新实现,以便访问底层 Columns 数据,供 StructScan 使用

type Rows

type Rows = core.Rows // Rows 是 sql.Rows 的封装,在循环 StructScan 期间缓存高开销的反射操作

type Rowsi

type Rowsi = core.Rowsi // Rowsi 是统一的行迭代接口

type Schema

type Schema = orm.Schema

type Session

type Session = orm.Session

type Stmt

type Stmt = db.Stmt // Stmt 是 sql.Stmt 的 dbx 封装,提供额外的功能

type Tx

type Tx = db.Tx // Tx 是 sql.Tx 的 dbx 封装,提供额外的功能

Directories

Path Synopsis
Package core 定义了 dbx 的领域层接口与核心类型。
Package core 定义了 dbx 的领域层接口与核心类型。
Package db 提供了 dbx 的基础设施层实现。
Package db 提供了 dbx 的基础设施层实现。
Package reflectx 实现了对标准 reflect 库的扩展,适用于实现序列化和 反序列化包。
Package reflectx 实现了对标准 reflect 库的扩展,适用于实现序列化和 反序列化包。
Package types 提供了一些实现了`sql.Scanner`和`sql.Valuer`接口的实例类型 适合作为 databases/sql 的扫描和赋值目标。
Package types 提供了一些实现了`sql.Scanner`和`sql.Valuer`接口的实例类型 适合作为 databases/sql 的扫描和赋值目标。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL