2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:34:15 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00
2026-03-07 19:27:44 +08:00

StarDB

一个轻量级的 Go 数据库封装库,个人学习用,提供简洁的 API 和 ORM 功能。

Go Version License

特性

  • 零第三方依赖 - 仅使用 Go 标准库
  • 类型安全 - 提供类型安全的结果转换方法
  • 简单 ORM - 支持结构体与数据库的自动映射
  • Context 支持 - 所有操作都支持 context
  • 事务支持 - 完整的事务操作支持
  • 预编译语句 - 支持预编译语句以提升性能
  • 批量操作 - 高效的批量插入功能
  • 连接池管理 - 便捷的连接池配置
  • 查询构建器 - 链式调用构建 SQL 查询

📦 安装

go get b612.me/stardb

🚀 快速开始

基本使用

package main

import (
    "b612.me/stardb"
    _ "github.com/mattn/go-sqlite3"
)

func main() {
    // 创建数据库实例
    db := stardb.NewStarDB()
    err := db.Open("sqlite3", "test.db")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 执行查询
    rows, err := db.Query("SELECT * FROM users WHERE age > ?", 18)
    if err != nil {
        panic(err)
    }
    defer rows.Close()

    // 遍历结果
    for i := 0; i < rows.Length(); i++ {
        row := rows.Row(i)
        name := row.MustString("name")
        age := row.MustInt("age")
        println(name, age)
    }
}

ORM 使用

package main

import (
    "b612.me/stardb"
    "time"
    _ "github.com/mattn/go-sqlite3"
)

// 定义结构体
type User struct {
    ID        int64     `db:"id"`
    Name      string    `db:"name"`
    Email     string    `db:"email"`
    Age       int       `db:"age"`
    Active    bool      `db:"active"`
    CreatedAt time.Time `db:"created_at"`
}

func main() {
    db := stardb.NewStarDB()
    db.Open("sqlite3", "test.db")
    defer db.Close()

    // 查询单个对象
    rows, _ := db.Query("SELECT * FROM users WHERE id = ?", 1)
    defer rows.Close()
    
    var user User
    rows.Orm(&user)
    println(user.Name)

    // 查询多个对象
    rows2, _ := db.Query("SELECT * FROM users WHERE age > ?", 18)
    defer rows2.Close()
    
    var users []User
    rows2.Orm(&users)
    
    for _, u := range users {
        println(u.Name, u.Age)
    }
}

插入和更新

// 插入数据
user := User{
    Name:      "Alice",
    Email:     "alice@example.com",
    Age:       25,
    Active:    true,
    CreatedAt: time.Now(),
}

result, err := db.Insert(&user, "users", "id") // "id" 是自增字段
if err != nil {
    panic(err)
}

lastID, _ := result.LastInsertId()
println("插入的 ID:", lastID)

// 更新数据
user.Age = 26
result, err = db.Update(&user, "users", "id") // "id" 是主键
if err != nil {
    panic(err)
}

affected, _ := result.RowsAffected()
println("更新的行数:", affected)

批量插入

// 方式 1使用原始数据
columns := []string{"name", "email", "age"}
values := [][]interface{}{
    {"Alice", "alice@example.com", 25},
    {"Bob", "bob@example.com", 30},
    {"Charlie", "charlie@example.com", 35},
}

result, err := db.BatchInsert("users", columns, values)
if err != nil {
    panic(err)
}

// 方式 2使用结构体
users := []User{
    {Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
    {Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
    {Name: "Charlie", Email: "charlie@example.com", Age: 35, CreatedAt: time.Now()},
}

result, err = db.BatchInsertStructs("users", users, "id")
if err != nil {
    panic(err)
}

affected, _ := result.RowsAffected()
println("批量插入行数:", affected)

事务操作

// 开始事务
tx, err := db.Begin()
if err != nil {
    panic(err)
}

// 执行操作
_, err = tx.Exec("INSERT INTO users (name, email) VALUES (?, ?)", "Alice", "alice@example.com")
if err != nil {
    tx.Rollback()
    panic(err)
}

_, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE user_id = ?", 100, 1)
if err != nil {
    tx.Rollback()
    panic(err)
}

// 提交事务
err = tx.Commit()
if err != nil {
    panic(err)
}

预编译语句

// 创建预编译语句
stmt, err := db.Prepare("SELECT * FROM users WHERE age > ?")
if err != nil {
    panic(err)
}
defer stmt.Close()

// 多次执行
rows1, _ := stmt.Query(18)
defer rows1.Close()

rows2, _ := stmt.Query(25)
defer rows2.Close()

rows3, _ := stmt.Query(30)
defer rows3.Close()

查询构建器

// 使用查询构建器
rows, err := stardb.NewQueryBuilder("users").
    Select("id", "name", "email").
    Where("age > ?", 18).
    Where("active = ?", true).
    OrderBy("name ASC").
    Limit(10).
    Offset(0).
    Query(db)

if err != nil {
    panic(err)
}
defer rows.Close()

var users []User
rows.Orm(&users)

连接池配置

// 方式 1使用默认配置
db, err := stardb.OpenWithPool("sqlite3", "test.db", nil)
if err != nil {
    panic(err)
}
defer db.Close()

// 方式 2自定义配置
config := &stardb.PoolConfig{
    MaxOpenConns:    50,              // 最大打开连接数
    MaxIdleConns:    10,              // 最大空闲连接数
    ConnMaxLifetime: 1 * time.Hour,   // 连接最大生命周期
    ConnMaxIdleTime: 10 * time.Minute, // 连接最大空闲时间
}

db, err = stardb.OpenWithPool("mysql", "user:pass@tcp(localhost:3306)/dbname", config)
if err != nil {
    panic(err)
}
defer db.Close()

// 方式 3手动设置
db := stardb.NewStarDB()
db.Open("postgres", "postgres://user:pass@localhost/dbname")
db.SetPoolConfig(config)

命名参数绑定

user := User{
    Name: "Alice",
    Age:  25,
}

// 使用 :fieldname 语法绑定结构体字段
rows, err := db.QueryX(&user, 
    "SELECT * FROM users WHERE name = ? AND age > ?", 
    ":name", ":age")
if err != nil {
    panic(err)
}
defer rows.Close()

📖 详细文档

结果转换方法

StarDB 提供了丰富的类型转换方法:

row := rows.Row(0)

// 字符串
name := row.MustString("name")

// 整数
age := row.MustInt("age")
id := row.MustInt64("id")
count := row.MustInt32("count")
uid := row.MustUint64("uid")

// 浮点数
price := row.MustFloat64("price")
rate := row.MustFloat32("rate")

// 布尔值
active := row.MustBool("active")

// 字节数组
data := row.MustBytes("data")

// 时间
createdAt := row.MustDate("created_at", "2006-01-02 15:04:05")

// 检查 NULL
isNull := row.IsNil("optional_field")

列操作

// 获取某一列的所有值
col := rows.Col("name")

names := col.MustString()    // []string
ages := col.MustInt()        // []int
prices := col.MustFloat64()  // []float64
actives := col.MustBool()    // []bool

Context 支持

所有操作都有对应的 Context 版本:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// 查询
rows, err := db.QueryContext(ctx, "SELECT * FROM users")

// 执行
result, err := db.ExecContext(ctx, "UPDATE users SET age = ?", 26)

// 事务
tx, err := db.BeginTx(ctx, nil)

// 批量插入
result, err := db.BatchInsertContext(ctx, "users", columns, values)

错误处理

// 使用 Must* 方法(忽略错误,返回零值)
name := row.MustString("name")

// 使用 Get* 方法(返回错误)
name, err := row.GetString("name")
if err != nil {
    // 处理错误
}

🔧 高级用法

嵌套结构体

type Profile struct {
    Bio    string `db:"bio"`
    Avatar string `db:"avatar"`
}

type User struct {
    ID      int64   `db:"id"`
    Name    string  `db:"name"`
    Profile Profile `db:"---"` // 使用 "---" 标记嵌套结构体
}

rows, _ := db.Query("SELECT id, name, bio, avatar FROM users")
defer rows.Close()

var user User
rows.Orm(&user)

println(user.Name)
println(user.Profile.Bio)

手动扫描模式

db := stardb.NewStarDB()
db.ManualScan = true // 启用手动扫描模式
db.Open("sqlite3", "test.db")

rows, _ := db.Query("SELECT * FROM users")
defer rows.Close()

// 手动触发解析
rows.Rescan()

// 现在可以访问数据
println(rows.Length())

直接访问底层 *sql.DB

db := stardb.NewStarDB()
db.Open("sqlite3", "test.db")

// 获取底层 *sql.DB
rawDB := db.DB()
rawDB.SetMaxOpenConns(100)

// 或者使用已有的 *sql.DB
sqlDB, _ := sql.Open("sqlite3", "test.db")
db := stardb.NewStarDBWithDB(sqlDB)

🎯 性能优化建议

1. 使用预编译语句

对于重复执行的查询,使用预编译语句可以提升 20-50% 的性能:

stmt, _ := db.Prepare("SELECT * FROM users WHERE id = ?")
defer stmt.Close()

for _, id := range userIDs {
    rows, _ := stmt.Query(id)
    // 处理结果
    rows.Close()
}

2. 批量操作

批量插入比单条插入快 2-3 倍:

// ❌ 慢
for _, user := range users {
    db.Exec("INSERT INTO users (name) VALUES (?)", user.Name)
}

// ✅ 快
db.BatchInsertStructs("users", users, "id")

3. 合理配置连接池

config := &stardb.PoolConfig{
    MaxOpenConns:    25,  // 根据数据库服务器调整
    MaxIdleConns:    5,   // 保持少量空闲连接
    ConnMaxLifetime: 1 * time.Hour,
    ConnMaxIdleTime: 10 * time.Minute,
}
db.SetPoolConfig(config)

4. 使用事务

将多个操作放在一个事务中可以显著提升性能:

tx, _ := db.Begin()
for _, user := range users {
    tx.Exec("INSERT INTO users (name) VALUES (?)", user.Name)
}
tx.Commit()

🧪 测试

项目包含完整的单元测试:

# 运行所有测试
cd testing
go test -v

# 运行特定测试
go test -v -run TestStarDB_Query

# 查看覆盖率
go test -cover

# 生成覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out

# 运行基准测试
go test -bench=. -benchmem

📊 支持的数据库

StarDB 支持所有实现了 database/sql 接口的数据库驱动:

数据库 驱动 导入
SQLite modernc.org/sqlite _ "modernc.org/sqlite"
MySQL github.com/go-sql-driver/mysql _ "github.com/go-sql-driver/mysql"
PostgreSQL github.com/lib/pq _ "github.com/lib/pq"
SQL Server github.com/denisenkom/go-mssqldb _ "github.com/denisenkom/go-mssqldb"
Oracle github.com/sijms/go-ora/v2 _ "github.com/sijms/go-ora/v2"

📄 许可证

本项目采用 Apache 2.0 许可证 - 详见 LICENSE 文件

🙏 致谢

  • 感谢 Go 标准库提供的 database/sql
  • 灵感来源于 xorm、gorm 等优秀的 ORM 框架

📮 联系方式

Description
No description provided
Readme Apache-2.0 160 KiB
v1.2.1 Latest
2026-03-20 13:38:19 +08:00
Languages
Go 100%