stardb/README.MD
2026-03-07 19:27:44 +08:00

535 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# StarDB
一个轻量级的 Go 数据库封装库,个人学习用,提供简洁的 API 和 ORM 功能。
[![Go Version](https://img.shields.io/badge/Go-%3E%3D%201.16-blue)](https://golang.org/)
[![License](https://img.shields.io/badge/license-Apache%20License%202.0-blue)](LICENSE)
## ✨ 特性
-**零第三方依赖** - 仅使用 Go 标准库
-**类型安全** - 提供类型安全的结果转换方法
-**简单 ORM** - 支持结构体与数据库的自动映射
-**Context 支持** - 所有操作都支持 context
-**事务支持** - 完整的事务操作支持
-**预编译语句** - 支持预编译语句以提升性能
-**批量操作** - 高效的批量插入功能
-**连接池管理** - 便捷的连接池配置
-**查询构建器** - 链式调用构建 SQL 查询
## 📦 安装
```bash
go get b612.me/stardb
```
## 🚀 快速开始
### 基本使用
```go
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 使用
```go
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)
}
}
```
### 插入和更新
```go
// 插入数据
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)
```
### 批量插入
```go
// 方式 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)
```
### 事务操作
```go
// 开始事务
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)
}
```
### 预编译语句
```go
// 创建预编译语句
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()
```
### 查询构建器
```go
// 使用查询构建器
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)
```
### 连接池配置
```go
// 方式 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)
```
### 命名参数绑定
```go
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 提供了丰富的类型转换方法:
```go
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")
```
### 列操作
```go
// 获取某一列的所有值
col := rows.Col("name")
names := col.MustString() // []string
ages := col.MustInt() // []int
prices := col.MustFloat64() // []float64
actives := col.MustBool() // []bool
```
### Context 支持
所有操作都有对应的 Context 版本:
```go
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)
```
### 错误处理
```go
// 使用 Must* 方法(忽略错误,返回零值)
name := row.MustString("name")
// 使用 Get* 方法(返回错误)
name, err := row.GetString("name")
if err != nil {
// 处理错误
}
```
## 🔧 高级用法
### 嵌套结构体
```go
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)
```
### 手动扫描模式
```go
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
```go
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% 的性能:
```go
stmt, _ := db.Prepare("SELECT * FROM users WHERE id = ?")
defer stmt.Close()
for _, id := range userIDs {
rows, _ := stmt.Query(id)
// 处理结果
rows.Close()
}
```
### 2. 批量操作
批量插入比单条插入快 2-3 倍:
```go
// ❌ 慢
for _, user := range users {
db.Exec("INSERT INTO users (name) VALUES (?)", user.Name)
}
// ✅ 快
db.BatchInsertStructs("users", users, "id")
```
### 3. 合理配置连接池
```go
config := &stardb.PoolConfig{
MaxOpenConns: 25, // 根据数据库服务器调整
MaxIdleConns: 5, // 保持少量空闲连接
ConnMaxLifetime: 1 * time.Hour,
ConnMaxIdleTime: 10 * time.Minute,
}
db.SetPoolConfig(config)
```
### 4. 使用事务
将多个操作放在一个事务中可以显著提升性能:
```go
tx, _ := db.Begin()
for _, user := range users {
tx.Exec("INSERT INTO users (name) VALUES (?)", user.Name)
}
tx.Commit()
```
## 🧪 测试
项目包含完整的单元测试:
```bash
# 运行所有测试
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](LICENSE) 文件
## 🙏 致谢
- 感谢 Go 标准库提供的 `database/sql`
- 灵感来源于 xorm、gorm 等优秀的 ORM 框架
## 📮 联系方式
- 项目主页: https://git.b612.me/b612/stardb.git