小巧的 Golang 数据库操作库,内置 SQL Builder 与轻量 ORM。
- 多数据库驱动:SQLite3、MySQL、PostgreSQL、MS SQL、ClickHouse、Doris
- SQL Builder:SELECT/INSERT/UPDATE/DELETE/UNION/CREATE TABLE
- ORM 风格 API:Find/FindOne/Pages/Insert/Update/Delete/Replace
- 批量写入:BatchInsert/BatchReplace
- 结果扫描:Scan/ScanToMap/QueryTo/QueryToMaps
- 事务、连接池、读写分离集群、迁移辅助
- Go 1.24+(go.mod)
- 依赖:zlsgo 及对应数据库驱动
go get github.com/zlsgo/zdb| 数据库 | 包路径 | 说明 |
|---|---|---|
| SQLite | github.com/zlsgo/zdb/driver/sqlite3 |
默认驱动,cgo 使用 mattn/go-sqlite3;非 cgo 使用 modernc.org/sqlite |
| MySQL | github.com/zlsgo/zdb/driver/mysql |
|
| PostgreSQL | github.com/zlsgo/zdb/driver/postgres |
|
| MS SQL | github.com/zlsgo/zdb/driver/mssql |
|
| ClickHouse | github.com/zlsgo/zdb/driver/clickhouse |
需要 -tags clickhouse |
| Doris | github.com/zlsgo/zdb/driver/doris |
需要 -tags doris |
补充:
- SQLite 可使用
CGO_ENABLED=1获得更好的性能 - Builder 默认驱动为 SQLite,可用
-tags nosqlite切换为 MySQL
package main
import (
"github.com/zlsgo/zdb"
"github.com/zlsgo/zdb/driver/sqlite3"
)
func main() {
cfg := &sqlite3.Config{File: "./test.db"}
zdb.Debug.Store(true)
db, err := zdb.New(cfg)
if err != nil {
panic(err)
}
_ = db
}cfg := &sqlite3.Config{File: "./data.db", ForeignKeys: true}
db, err := zdb.New(cfg)cfg := &mysql.Config{
Host: "127.0.0.1",
Port: 3306,
User: "root",
Password: "password",
DBName: "demo",
Charset: "utf8mb4",
}
db, err := zdb.New(cfg)cfg := &postgres.Config{
Host: "127.0.0.1",
Port: 5432,
User: "postgres",
Password: "password",
DBName: "demo",
SSLMode: "disable",
}
db, err := zdb.New(cfg)cfg := &mssql.Config{
Host: "127.0.0.1",
Port: 1433,
User: "sa",
Password: "password",
DBName: "demo",
}
db, err := zdb.New(cfg)ClickHouse 示例需要 -tags clickhouse 构建后使用。
cfg := &clickhouse.Config{
Host: "127.0.0.1",
Port: 9000,
User: "default",
Password: "",
DBName: "default",
Compress: true,
}
db, err := zdb.New(cfg)Doris 示例需要 -tags doris 构建后使用。
cfg := &doris.Config{
Host: "127.0.0.1",
Port: 9030,
User: "root",
Password: "",
DBName: "demo",
}
db, err := zdb.New(cfg)自定义 DSN 可使用 SetDsn 覆盖自动拼接结果。
type User struct {
ID int `zdb:"id"`
Name string `zdb:"name"`
CreatedAt zdb.JsonTime `zdb:"created_at"`
}
res, err := db.Exec("INSERT INTO user(name) VALUES(?)", "hi")
rows, err := db.Query("SELECT * FROM user WHERE name = ?", "hi")
if err != nil {
panic(err)
}
defer rows.Close()
var users []User
count, err := zdb.Scan(rows, &users)maps, err := db.QueryToMaps("SELECT * FROM user WHERE id > ?", 0)
var out []User
err = db.QueryTo(&out, "SELECT * FROM user WHERE id > ?", 0)rows, err := db.Find("user", func(b *builder.SelectBuilder) error {
b.Where(b.Cond.GE("id", 1))
b.OrderBy("id").Desc()
b.Limit(10)
return nil
})
row, err := db.FindOne("user", func(b *builder.SelectBuilder) error {
b.Where(b.Cond.EQ("id", 1))
return nil
})rows, pages, err := db.Pages("user", 1, 20, func(b *builder.SelectBuilder) error {
b.OrderBy("id").Desc()
return nil
})id, err := db.Insert("user", map[string]interface{}{"name": "hi", "age": 18})
ids, err := db.BatchInsert("user", []map[string]interface{}{
{"name": "a", "age": 18},
{"name": "b", "age": 20},
})
id, err = db.Replace("user", map[string]interface{}{"id": 1, "name": "hi"})n, err := db.Update("user", map[string]interface{}{"name": "new"}, func(b *builder.UpdateBuilder) error {
b.Where(b.Cond.EQ("id", 1))
return nil
})
n, err = db.Delete("user", func(b *builder.DeleteBuilder) error {
b.Where(b.Cond.EQ("id", 1))
return nil
})err := db.Transaction(func(tx *zdb.DB) error {
_, err := tx.Exec("UPDATE user SET name = ? WHERE id = ?", "hi", 1)
return err
})db, err := zdb.NewCluster([]driver.IfeConfig{cfg1, cfg2, cfg3}, "main")
err = db.Source(func(e *zdb.DB) error {
_, err := e.Exec("INSERT INTO user(name) VALUES(?)", "source")
return err
})
err = db.Replica(func(e *zdb.DB) error {
_, err := e.Query("SELECT * FROM user")
return err
})
ref := zdb.Instance("main")err := db.Migration(func(db *zdb.DB, d driver.Dialect) error {
sql, args, has := d.HasTable("user")
rows, err := db.QueryToMaps(sql, args...)
if err != nil {
return err
}
if !has(rows) {
return nil
}
return nil
})tb := builder.CreateTable("user").
IfNotExists().
Column(
schema.NewField("id", schema.Int, func(f *schema.Field) { f.PrimaryKey = true; f.AutoIncrement = true }),
schema.NewField("name", schema.String),
)
sql, args, err := tb.Build()
if err != nil {
panic(err)
}
_, err = db.Exec(sql, args...)builder.Build("... a=$? AND b=$?", 1, "x")builder.BuildNamed("... a=${a} AND b=${b}", map[string]interface{}{"a": 1, "b": "x"})builder.Select/Query/Insert/Update/Delete/Union/CreateTableb.Cond:EQ/NE/GT/GE/LT/LE/In/NotIn/Like/Between/And/Or/IsNull/IsNotNull(各 Builder 回调内)builder.Raw用于嵌入原生表达式,builder.Named用于命名参数
Find/FindOne/Scan/QueryTo(非 slice) 在无结果时返回ErrNotFoundUpdate/Delete必须带Where条件;非 MySQL 使用Limit时需要LimitBy- PostgreSQL 插入会使用
RETURNING,默认主键字段为id,可用SetIDKey修改 Replace/BatchReplace使用 REPLACE 语法(MySQL 风格),请确认目标数据库支持
zdb.Debug.Store(true)
db.Debug = true
db.Options(func(o *zdb.Options) {
o.MaxIdleConns = 10
o.MaxOpenConns = 100
o.ConnMaxLifetime = time.Minute * 30
})