Skip to content

dataixcom/gdbx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gdbx - Go Database Extension

gdbx 是一个 Go 语言数据库操作扩展库,提供通用的数据库 CRUD 操作、SQL 生成、连接池管理和多数据库适配能力。支持 MySQL、Oracle、PostgreSQL、SQLite、DM8(达梦) 五种数据库,采用依赖注入设计,与外部系统保持松耦合。

核心特性

  • 多数据库支持 - MySQL、Oracle、PostgreSQL、SQLite、DM8 统一 API
  • 依赖注入 - 数据库连接和日志实例均支持外部注入
  • 连接池管理 - 内置连接池,支持外部连接注册和过期清理
  • 泛型 Repository - 通用 CRUD 操作,无需手写 SQL
  • SQL Builder - 链式调用构建复杂查询
  • 日志抽象 - 统一日志接口,兼容主流 Go 日志库
  • Options 模式 - 灵活的配置方式
  • 可扩展 - 通过 DatabaseFactory 接口轻松添加新数据库适配

环境要求

  • Go 1.22+
  • SQLite 需要 CGO 支持(CGO_ENABLED=1

安装

go get github.com/dataixcom/gdbx

快速开始

1. 使用 DSN 配置(自动创建连接)

import (
    gdbx "github.com/dataixcom/gdbx"
    "github.com/dataixcom/gdbx/base/config"
    "github.com/dataixcom/gdbx/base/repository"
)

dsnCfg := config.DSNConfig{
    DBType:   config.MySQL,
    Host:     "localhost",
    Port:     3306,
    User:     "root",
    Password: "password",
    Schema:   "testdb",
    MaxIdle:  5,
    MaxOpen:  20,
}

repo, err := repository.NewGenericRepository(dsnCfg)
if err != nil {
    log.Fatal(err)
}

2. 注入外部数据库连接

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    gdbx "github.com/dataixcom/gdbx"
    "github.com/dataixcom/gdbx/base/config"
    "github.com/dataixcom/gdbx/base/repository"
)

db, err := sql.Open("mysql", "root:password@tcp(localhost:3306)/testdb?parseTime=true")
if err != nil {
    log.Fatal(err)
}

repo, err := repository.NewGenericRepositoryWithDB(db, config.MySQL)
if err != nil {
    log.Fatal(err)
}

executor, err := gdbx.NewQueryExecutor(
    gdbx.WithDB(db, config.MySQL),
)

3. 注入日志实例

import (
    "log/slog"
    "os"
    "github.com/dataixcom/gdbx/base/logger"
    "github.com/dataixcom/gdbx/base/repository"
    "github.com/dataixcom/gdbx/base/template"
    gdbx "github.com/dataixcom/gdbx"
)

customLogger := logger.NewLoggerFromSlog(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelDebug,
})))

repo, err := repository.NewGenericRepositoryWithDB(db, config.MySQL,
    repository.WithRepositoryLogger(customLogger),
)

tmpl, err := template.NewSQLExecutorTemplateWithDB(db, config.MySQL,
    template.WithTemplateLogger(customLogger),
)

executor, err := gdbx.NewQueryExecutor(
    gdbx.WithDB(db, config.MySQL),
    gdbx.WithLogger(customLogger),
)

数据库支持

支持的数据库

数据库 DBType 常量 驱动 标识符引用 UPSERT 语法 分页语法
MySQL config.MySQL go-sql-driver/mysql `name` ON DUPLICATE KEY UPDATE LIMIT/OFFSET
Oracle config.Oracle go-ora/v2 "name" MERGE INTO ... USING (SELECT FROM DUAL) ROWNUM
PostgreSQL config.Postgres pgx/v5 "name" ON CONFLICT DO UPDATE LIMIT/OFFSET
SQLite config.SQLite glebarez/sqlite (纯Go) "name" ON CONFLICT DO UPDATE LIMIT/OFFSET
DM8 (达梦) config.DM8 gitee.com/chunanyong/dm "name" MERGE INTO ... USING (SELECT FROM DUAL) LIMIT/OFFSET

SQLite 使用示例

import (
    "database/sql"
    _ "github.com/glebarez/sqlite"
    "github.com/dataixcom/gdbx/base/config"
    "github.com/dataixcom/gdbx/base/repository"
)

// 文件数据库
dsnCfg := config.DSNConfig{
    DBType: config.SQLite,
    Schema: "/path/to/database.db",
}

// 内存数据库
dsnCfg := config.DSNConfig{
    DBType: config.SQLite,
    Schema: ":memory:",
}

// 或注入已有连接
db, _ := sql.Open("sqlite3", ":memory:")
repo, _ := repository.NewGenericRepositoryWithDB(db, config.SQLite)

注意: SQLite 需要 CGO 支持。编译时需设置 CGO_ENABLED=1。默认 MaxOpenConns=1 以避免并发写入问题。

DM8 (达梦) 使用示例

import (
    "database/sql"
    _ "gitee.com/chunanyong/dm"
    "github.com/dataixcom/gdbx/base/config"
    "github.com/dataixcom/gdbx/base/repository"
    "github.com/dataixcom/gdbx/dm8"
)

// 通过 DSN 配置
dsnCfg := config.DSNConfig{
    DBType:   config.DM8,
    Host:     "localhost",
    Port:     5236,
    User:     "SYSDBA",
    Password: "SYSDBA001",
    Schema:   "TESTDB",
}

// 或注入已有连接
db, _ := sql.Open("dm", "dm://SYSDBA:SYSDBA001@localhost:5236/TESTDB")
repo, _ := repository.NewGenericRepositoryWithDB(db, config.DM8)

// 自定义驱动名称
factory := dm8.NewDM8Factory("dm8_custom")

扩展新数据库

通过实现 DatabaseFactory 接口添加新数据库适配:

import (
    "github.com/dataixcom/gdbx/base/config"
    "github.com/dataixcom/gdbx/base/factory"
)

type MyDBFactory struct{}

func (f *MyDBFactory) CreateSQLGenerator() strategy.SQLGenerator { ... }
func (f *MyDBFactory) CreateSQLExecutor(db *sql.DB) strategy.SQLExecutor { ... }
func (f *MyDBFactory) CreateMetadataProvider(db *sql.DB) metadata.MetadataProvider { ... }
func (f *MyDBFactory) OpenDB(dsnCfg config.DSNConfig) (*sql.DB, error) { ... }
func (f *MyDBFactory) GetDBType() config.DBType { return config.DBType("mydb") }

// 注册到工厂
factory.RegisterDatabaseFactory(config.DBType("mydb"), &MyDBFactory{})

数据库连接注入

DBConnector 接口

gdbx 定义了 DBConnector 接口,标准库的 *sql.DB 自动满足该接口:

type DBConnector interface {
    QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
    ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
    QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
    BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
    PingContext(ctx context.Context) error
    Close() error
    SetMaxOpenConns(n int)
    SetMaxIdleConns(n int)
    SetConnMaxLifetime(d time.Duration)
    SetConnMaxIdleTime(d time.Duration)
    Stats() sql.DBStats
}

连接验证

err := gdbx.ValidateDBConnector(db)
if err != nil {
    log.Fatalf("数据库连接无效: %v", err)
}

连接池注册

import "github.com/dataixcom/gdbx/base/pool"

// 推荐方式:使用 ConnectionManager
cm := pool.DefaultConnectionManager()
cm.RegisterConnection("my-service-db", db, config.MySQL)
cm.RegisterConnectionWithDSN(dsnCfg, db)
err := cm.RegisterConnectionWithValidation("my-service-db", db, config.MySQL)

// 兼容方式:包级函数(委托给 DefaultConnectionManager)
pool.RegisterDBWithDSN(dsnCfg, db)
pool.RegisterDB("my-service-db", db, config.MySQL)
err := pool.RegisterDBWithValidation("my-service-db", db, config.MySQL)

ConnectionManager(推荐)

ConnectionManager 是统一的连接管理核心,所有包级函数均委托给全局默认 ConnectionManager 实例。

import "github.com/dataixcom/gdbx/base/pool"

// 创建自定义 ConnectionManager
cm := pool.NewConnectionManagerWithLogger(customLogger)

// 启用自动过期清理(后台 goroutine 定期清理)
cm.WithAutoCleanup(5 * time.Minute)
defer cm.StopAutoCleanup()

// 注册外部连接
cm.RegisterConnection("service-a", dbA, config.MySQL)
cm.RegisterConnection("service-b", dbB, config.DM8)

// 获取连接(自动创建或复用已有连接)
db, err := cm.GetConnection(dsnCfg)

// 健康检查
healthy, msg := cm.GetConnectionHealth(ctx, dsnCfg)
health := cm.GetAllConnectionHealth(ctx)

// 连接管理
count := cm.GetActiveConnectionCount()
removed := cm.RemoveExpiredConnections()
cm.CloseConnection(dsnCfg)
cm.CloseAll()

// 设置自定义 ConnectionManager 为全局默认
pool.SetDefaultConnectionManager(cm)

// 获取当前默认 ConnectionManager
defaultCM := pool.DefaultConnectionManager()

连接池选项

executor, err := gdbx.NewQueryExecutor(
    gdbx.WithDSNConfig(dsnCfg),
    gdbx.WithPoolOptions(gdbx.PoolOptions{
        MaxOpenConns:    25,
        MaxIdleConns:    10,
        ConnMaxLifetime: 5 * time.Minute,
        ConnMaxIdleTime: 1 * time.Minute,
    }),
)

日志配置与注入

Logger 接口

type Logger interface {
    Debug(msg string, args ...interface{})
    Info(msg string, args ...interface{})
    Warn(msg string, args ...interface{})
    Error(msg string, args ...interface{})
    With(args ...interface{}) Logger
}

日志适配器

适配器 说明
logger.NewLoggerFromSlog(l *slog.Logger) *slog.Logger 创建 Logger
gdbx.WrapSlog(l *slog.Logger) 顶层 API 包装 slog
logger.NewNopLogger() 静默日志(不输出)
logger.NewDBLogger(l *slog.Logger) 数据库专用日志(含慢查询追踪)

全局默认日志

logger.SetDefault(customLogger)
l := logger.GetDefault()

DBLogger 慢查询追踪

dbLogger := logger.NewDBLogger(slog.Default(), logger.LogLevelInfo)
dbLogger.Trace(ctx, startTime, func() (string, int64) {
    return sql, rowsAffected
}, err)

日志级别

const (
    LogLevelSilent LogLevel = iota + 1  // 静默
    LogLevelError                        // 仅错误
    LogLevelWarn                         // 警告及以上
    LogLevelInfo                         // 全部
)

API 接口文档

顶层 API (gdbx 包)

函数 说明
NewQueryExecutor(opts ...Option) 创建 SQL 执行器
NewSQLGenerator(dbType) 创建 SQL 生成器
NewMetadataProvider(opts ...Option) 创建元数据提供者
ValidateDBConnector(db) 验证数据库连接
WrapSlog(l *slog.Logger) 包装 slog 为 Logger
NewNopLogger() 创建静默日志

Option 函数

Option 说明
WithDB(db, dbType) 注入外部数据库连接
WithDSNConfig(dsnCfg) 使用 DSN 配置自动创建连接
WithLogger(l) 注入 Logger 实例
WithSlogLogger(l) 注入 *slog.Logger
WithPoolOptions(opts) 配置连接池参数

GenericRepository

repo, _ := repository.NewGenericRepository(dsnCfg)
repo, _ := repository.NewGenericRepositoryWithDB(db, dbType, WithRepositoryLogger(l))

results, err := repo.FindAll(selectCfg)
result, err := repo.FindById(selectCfg)
affected, err := repo.Insert(insertCfg)
affected, err := repo.Update(updateCfg)
affected, err := repo.Delete(deleteCfg)
count, err := repo.Count(selectCfg)
exists, err := repo.Exists(selectCfg)

affected, err := repo.BatchInsert(batchInsertCfg)
affected, err := repo.BatchUpdate(batchUpdateCfg)
affected, err := repo.Upsert(upsertCfg)
affected, err := repo.BatchUpsert(batchUpsertCfg)

pageResult, err := repo.PageQuery(pageCfg)
results, err := repo.ExecuteRawQuery(sql)
affected, err := repo.ExecuteRawExec(sql)

repo.SetLogger(customLogger)
l := repo.GetLogger()

连接池 (pool 包)

ConnectionManager(推荐)

方法 说明
NewConnectionManager() 创建连接管理器
NewConnectionManagerWithLogger(l) 创建带日志的连接管理器
cm.RegisterConnection(key, db, dbType) 注册外部连接
cm.RegisterConnectionWithDSN(dsnCfg, db) 通过 DSN 注册连接
cm.RegisterConnectionWithValidation(key, db, dbType) 带验证的注册
cm.UnregisterConnection(key) 取消注册
cm.GetConnection(dsnCfg) 获取连接(自动创建或复用)
cm.GetConnectionWithContext(ctx, dsnCfg) 带上下文获取连接
cm.GetActiveConnectionCount() 获取活跃连接数
cm.RemoveExpiredConnections() 清理过期连接
cm.CloseConnection(dsnCfg) 关闭指定连接
cm.CloseAll() 关闭所有连接
cm.Ping(ctx, dsnCfg) 检查连接可用性
cm.GetConnectionHealth(ctx, dsnCfg) 获取连接健康状态
cm.GetAllConnectionHealth(ctx) 获取所有连接健康状态
cm.WithAutoCleanup(interval) 启用自动过期清理
cm.StopAutoCleanup() 停止自动清理
cm.SetLogger(l) 设置日志实例
DefaultConnectionManager() 获取全局默认 ConnectionManager
SetDefaultConnectionManager(cm) 设置全局默认 ConnectionManager

包级函数(兼容,委托给 DefaultConnectionManager)

函数 说明
RegisterDB(key, db, dbType) 注册外部连接(Deprecated)
RegisterDBWithDSN(dsnCfg, db) 通过 DSN 注册连接(Deprecated)
RegisterDBWithValidation(key, db, dbType) 带验证的注册(Deprecated)
UnregisterDB(key) 取消注册(Deprecated)
GetDBPool(dsnCfg) 获取连接池(Deprecated)
GetDBPoolWithContext(ctx, dsnCfg) 带上下文获取连接池(Deprecated)
GetDBConnection(dsnCfg) 获取连接(Deprecated)
GetActiveConnectionCount() 获取活跃连接数(Deprecated)
RemoveExpiredConnections() 清理过期连接(Deprecated)
CloseAllConnections() 关闭所有连接(Deprecated)

项目结构

gdbx/
├── gdbx.go                          # 顶层 API,Options 模式,DBConnector 接口
├── base/
│   ├── config/                      # 数据库配置,DSN,Where 子句构建
│   ├── logger/                      # 日志接口,适配器,DBLogger
│   ├── pool/                        # 连接池管理,ConnectionManager
│   ├── factory/                     # 数据库工厂模式
│   ├── repository/                  # 通用 Repository
│   ├── template/                    # SQL 执行模板
│   ├── strategy/                    # SQL 生成和执行策略
│   ├── builder/                     # SQL Builder
│   ├── adapter/                     # 数据库适配器
│   ├── decorator/                   # 查询装饰器
│   ├── metadata/                    # 数据库元数据
│   ├── observer/                    # 事件观察者
│   └── utils/                       # 工具函数
├── mysql/                           # MySQL 适配器
├── oracle/                          # Oracle 适配器
├── postgres/                        # PostgreSQL 适配器
├── sqlite/                          # SQLite 适配器
├── dm8/                             # DM8(达梦)适配器
└── examples/                        # 示例代码
    ├── di_injection/                # 依赖注入示例
    ├── sqlite_demo/                 # SQLite 使用示例
    ├── dm8_demo/                    # DM8 使用示例
    ├── multi_db/                    # 多数据库示例
    ├── sql_builder/                 # SQL Builder 示例
    └── where_clause/                # Where 子句示例

FAQ

Q: 如何在已有项目中集成 gdbx?

推荐使用 WithDB 注入已有的数据库连接:

db := myApp.GetDB()
repo, _ := repository.NewGenericRepositoryWithDB(db, config.MySQL,
    repository.WithRepositoryLogger(myApp.GetLogger()),
)

Q: 如何自定义日志格式?

jsonLogger := logger.NewLoggerFromSlog(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelDebug,
})))
fileLogger, _ := logger.NewFileLogger("/var/log/gdbx.log")
rotateLogger, _ := logger.NewRotatingFileLogger("/var/log/gdbx.log", 100)

Q: 如何禁用日志?

nopLogger := logger.NewNopLogger()
repo.SetLogger(nopLogger)

Q: 支持哪些数据库?

目前支持 MySQL、Oracle、PostgreSQL、SQLite 和 DM8(达梦)。可通过实现 factory.DatabaseFactory 接口扩展其他数据库。

Q: SQLite 编译报错 "go-sqlite3 requires cgo"?

项目已使用纯 Go 实现的 SQLite 驱动 github.com/glebarez/sqlite,无需 CGO 支持。可直接编译:

go build ./...

如需切换回 CGO 驱动,修改 sqlite/sqlite_factory.go 中的导入即可。

Q: 如何使用 DM8(达梦)数据库?

DM8 驱动需要单独安装。推荐使用 dm8.NewDM8Factory(driverName) 指定驱动名称,并通过 database/sql.Open 注入已有连接:

import _ "gitee.com/chunanyong/dm"

db, _ := sql.Open("dm", "dm://SYSDBA:password@host:5236/schema")
repo, _ := repository.NewGenericRepositoryWithDB(db, config.DM8)

Q: 如何运行集成测试?

go test -tags=integration ./...

Q: 连接池中的外部连接会被自动关闭吗?

不会。通过 RegisterConnection 注册的外部连接(External=true)在 CloseAllRemoveExpiredConnections 时不会被关闭,需要由注册方自行管理生命周期。

Q: 包级函数和 ConnectionManager 有什么区别?

包级函数(如 GetDBPoolRegisterDB)已标记为 Deprecated,它们内部委托给全局默认 ConnectionManager 实例。推荐直接使用 ConnectionManager,它提供更完整的功能(自动清理、健康检查、并发安全的连接创建等)。可通过 pool.DefaultConnectionManager() 获取全局默认实例,或通过 pool.SetDefaultConnectionManager(cm) 设置自定义实例。

License

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages