本教程涵盖 TsDB2 时序数据库的所有核心操作,包括建表、增删改查、条件查询、索引管理、事务控制等。
TsDB2 使用 Go struct 定义数据模型,通过 tsdb tag 指定字段类型:
package main
import (
"TsDB2/DB"
"fmt"
)
// 员工表模型
type Employee struct {
DB.BaseModel // 必须嵌入,提供 ID 字段
Name string `tsdb:"32byte"` // 字符串字段,最大32字节
Age int64 `tsdb:"8byte"` // 整数字段,8字节
Score int64 `tsdb:"8byte"` // 整数字段,8字节
Dept string `tsdb:"16byte"` // 字符串字段,最大16字节
}
// 订单表模型
type Order struct {
DB.BaseModel
EmployeeID int64 `tsdb:"8byte"`
Amount int64 `tsdb:"8byte"`
Status int64 `tsdb:"8byte"` // 0=pending, 1=done, 2=cancel
}
支持的字段类型:
1byte ~ 256byte: 变长字符串/二进制8byte: int64 / uint644byte: int32 / uint322byte: int16 / uint161byte: int8 / uint8// 打开或创建数据库文件
db, err := DB.Open("mydb.db")
if err != nil {
panic(err)
}
defer db.Close() // 程序退出前关闭
// 设置自动提交延迟(防抖)
db.SetAutoCommitDelay(500 * time.Millisecond) // 500ms 后自动 Commit
// ✅ 推荐方式:自动推导表名(从类型名 Employee -> "employee")
empTbl, err := DB.UseTable[Employee](db)
if err != nil {
panic(err)
}
// 可选:手动指定表名
orderTbl, err := DB.UseTable[Order](db, "orders") // 自定义表名为 "orders"
if err != nil {
panic(err)
}
工作原理:
UseTable[Employee](db) → 自动推导表名为 "employee"(首字母小写)UseTable[OrderItem](db) → 自动推导表名为 "orderItem"UseTable[T](db, "custom_name") → 使用自定义表名TsDB2 支持多种索引类型:
// 获取表的底层 Core 对象
empCore, _ := db.CoreDB().FindTable("employee")
// 1️⃣ 主键 B+ 树索引(自动创建,基于 ID 字段)
// 无需手动创建,UseTable 时自动生成 pk_employee
// 2️⃣ 二级 B+ 树索引(单字段)
empCore.CreateIndex("idx_age", page.IndexTypeBTree, []byte{2}) // Age 字段索引
empCore.CreateIndex("idx_dept", page.IndexTypeBTree, []byte{4}) // Dept 字段索引
// 3️⃣ 时序索引(时间范围查询优化)
// empCore.CreateIndex("idx_time", page.IndexTypeTime, []byte{1})
// 4️⃣ 复合索引(多字段组合)
// empCore.CreateIndex("idx_age_dept", page.IndexTypeCompose, []byte{2, 4})
orderCore, _ := db.CoreDB().FindTable("order")
orderCore.CreateIndex("idx_status", page.IndexTypeBTree, []byte{3}) // Status 索引
索引类型说明:
IndexTypePrimary (2): 主键索引,叶子节点存 [Key → DataPage]IndexTypeBTree (5): 二级 B+ 树索引,叶子节点存 [Key → PKID]IndexTypeTime (1): 时序索引,优化时间范围查询IndexTypeCompose (4): 复合索引,多字段联合索引err := empTbl.Insert(&Employee{
Name: "张三",
Age: 25,
Score: 95,
Dept: "工程部",
})
if err != nil {
fmt.Printf("插入失败: %v\n", err)
}
// 插入 10000 条员工记录
for i := 1; i <= 10000; i++ {
err := empTbl.Insert(&Employee{
Name: fmt.Sprintf("Emp%07d", i),
Age: int64(20 + (i % 50)), // 年龄 20~69
Score: int64(i % 1000), // 分数 0~999
Dept: []string{"工程部", "销售部", "人事部", "财务部", "运维部"}[i%5],
})
if err != nil {
panic(fmt.Sprintf("插入第 %d 行失败: %v", i, err))
}
// 每 1000 行打印进度
if i%1000 == 0 {
fmt.Printf("已插入 %d 行\n", i)
}
}
// 禁用自动提交,手动控制 Commit 时机
db.SetAutoCommitDelay(0) // 禁用防抖
// 批量插入 10 万行
for i := 1; i <= 100000; i++ {
empTbl.Insert(&Employee{...})
}
// 一次性提交所有数据
fmt.Println("开始 Commit...")
t1 := time.Now()
if err := db.Commit(); err != nil {
panic(err)
}
fmt.Printf("Commit 完成,耗时: %.2fs\n", time.Since(t1).Seconds())
性能对比:
// 根据 ID 查询
emp, err := empTbl.Find(1)
if err != nil {
fmt.Printf("未找到 ID=1 的记录\n")
} else {
fmt.Printf("ID=%d, Name=%s, Age=%d, Score=%d, Dept=%s\n",
emp.ID, emp.Name, emp.Age, emp.Score, emp.Dept)
}
// WHERE Age = 25
rows, err := empTbl.Where("Age", "=", int64(25)).Find()
if err != nil {
panic(err)
}
fmt.Printf("找到 %d 名 25 岁的员工\n", len(rows))
for _, emp := range rows {
fmt.Printf(" - %s (Score: %d)\n", emp.Name, emp.Score)
}
// 全表扫描
allEmps, err := empTbl.Find() // 无条件,返回所有记录
if err != nil {
panic(err)
}
fmt.Printf("总共有 %d 名员工\n", len(allEmps))
// 循环处理
for i, emp := range allEmps {
if emp.Score >= 90 {
fmt.Printf("[%d] 优秀员工: %s, Score=%d\n", i+1, emp.Name, emp.Score)
}
}
// 更新 ID=1 的员工信息
err := empTbl.Update(&Employee{
BaseModel: DB.BaseModel{ID: 1}, // 必须指定 ID
Name: "李四",
Age: 30,
Score: 98,
Dept: "技术部",
})
if err != nil {
fmt.Printf("更新失败: %v\n", err)
}
// 验证更新
emp, _ := empTbl.Find(1)
fmt.Printf("更新后: Name=%s, Age=%d\n", emp.Name, emp.Age)
// 输出: 更新后: Name=李四, Age=30
// 给所有工程部员工加 10 分
emps, _ := empTbl.Where("Dept", "=", "工程部").Find()
for _, emp := range emps {
emp.Score += 10
empTbl.Update(emp)
}
fmt.Printf("已为 %d 名工程部员工加分\n", len(emps))
// 删除 ID=2 的员工
err := empTbl.Delete(2)
if err != nil {
fmt.Printf("删除失败: %v\n", err)
}
// 验证删除
_, err = empTbl.Find(2)
if err != nil {
fmt.Println("✅ ID=2 已成功删除")
}
// 删除所有分数低于 60 的员工
lowScores, _ := empTbl.Where("Score", "<", int64(60)).Find()
fmt.Printf("找到 %d 名低分员工\n", len(lowScores))
for _, emp := range lowScores {
empTbl.Delete(emp.ID)
}
fmt.Println("✅ 已删除所有低分员工")
// 验证
remaining, _ := empTbl.Count()
fmt.Printf("剩余员工数: %d\n", remaining)
// 删除部门时,同时删除该部门所有员工
deptToDelete := "临时工"
emps, _ := empTbl.Where("Dept", "=", deptToDelete).Find()
for _, emp := range emps {
empTbl.Delete(emp.ID)
}
fmt.Printf("已删除 %d 名 %s 员工\n", len(emps), deptToDelete)
// 等于 (=)
rows, _ := empTbl.Where("Age", "=", int64(25)).Find()
// 不等于 (!=)
rows, _ = empTbl.Where("Status", "!=", int64(0)).Find()
// 大于 (>)
rows, _ = empTbl.Where("Score", ">", int64(90)).Find()
// 大于等于 (>=)
rows, _ = empTbl.Where("Age", ">=", int64(30)).Find()
// 小于 (<)
rows, _ = empTbl.Where("Score", "<", int64(60)).Find()
// 小于等于 (<=)
rows, _ = empTbl.Where("Age", "<=", int64(25)).Find()
// WHERE Age >= 20 AND Age <= 30
rows, _ := empTbl.
Where("Age", ">=", int64(20)).
Where("Age", "<=", int64(30)).
Find()
fmt.Printf("20~30岁员工: %d 人\n", len(rows))
// WHERE Dept IN ("工程部", "技术部")
rows, _ := empTbl.Where("Dept", "in", []string{"工程部", "技术部"}).Find()
fmt.Printf("工程/技术部员工: %d 人\n", len(rows))
// WHERE Name LIKE "张%"
rows, _ := empTbl.Where("Name", "like", "张%").Find()
fmt.Printf("姓张的员工: %d 人\n", len(rows))
// WHERE Name LIKE "%三"
rows, _ = empTbl.Where("Name", "like", "%三").Find()
fmt.Printf("名字以'三'结尾的员工: %d 人\n", len(rows))
// WHERE Age > 25 AND Score >= 80 AND Dept = "工程部"
rows, _ := empTbl.
Where("Age", ">", int64(25)).
Where("Score", ">=", int64(80)).
Where("Dept", "=", "工程部").
Find()
fmt.Printf("符合条件的员工: %d 人\n", len(rows))
// 使用 OrCondition
import "TsDB2/DB/core"
cond := core.OrCondition{
core.EqCondition{Field: "Dept", Value: "工程部"},
core.EqCondition{Field: "Dept", Value: "技术部"},
}
rows, _ := empTbl.WhereCondition(cond).Find()
// ORDER BY Age ASC
rows, _ := empTbl.OrderBy("Age").Find()
fmt.Println("按年龄升序:")
for _, emp := range rows[:5] { // 只看前5条
fmt.Printf(" %s: %d岁\n", emp.Name, emp.Age)
}
// ORDER BY Score DESC
rows, _ := empTbl.OrderBy("Score", true).Find() // true = 降序
fmt.Println("按分数降序(前5名):")
for i, emp := range rows[:5] {
fmt.Printf(" [%d] %s: %d分\n", i+1, emp.Name, emp.Score)
}
// ORDER BY Age ASC LIMIT 10
rows, _ := empTbl.OrderBy("Age").Limit(10).Find()
fmt.Printf("最年轻的 10 名员工:\n")
for _, emp := range rows {
fmt.Printf(" %s: %d岁\n", emp.Name, emp.Age)
}
// 每页 20 条
pageSize := 20
// 第1页
page1, _ := empTbl.OrderBy("Age").Offset(0).Limit(pageSize).Find()
fmt.Printf("第1页: %d 条\n", len(page1))
// 第2页
page2, _ := empTbl.OrderBy("Age").Offset(pageSize).Limit(pageSize).Find()
fmt.Printf("第2页: %d 条\n", len(page2))
// 第3页
page3, _ := empTbl.OrderBy("Age").Offset(pageSize*2).Limit(pageSize).Find()
fmt.Printf("第3页: %d 条\n", len(page3))
func printPage(tbl *DB.Table[Employee], pageNum, pageSize int) {
offset := (pageNum - 1) * pageSize
rows, _ := tbl.OrderBy("Age").Offset(offset).Limit(pageSize).Find()
fmt.Printf("\n=== 第 %d 页 (共 %d 条) ===\n", pageNum, len(rows))
for _, emp := range rows {
fmt.Printf(" %-15s %2d岁 %3d分 %s\n",
emp.Name, emp.Age, emp.Score, emp.Dept)
}
}
// 打印前3页
for page := 1; page <= 3; page++ {
printPage(empTbl, page, 20)
}
// SELECT COUNT(*) FROM employee
total, err := empTbl.Count()
if err != nil {
panic(err)
}
fmt.Printf("员工总数: %d\n", total)
// 带条件的 COUNT
youngCount, _ := empTbl.Where("Age", "<", int64(25)).Count()
fmt.Printf("25岁以下员工: %d 人\n", youngCount)
// 最小年龄
minAgeRows, _ := empTbl.OrderBy("Age").Limit(1).Find()
if len(minAgeRows) > 0 {
fmt.Printf("最小年龄: %d岁 (%s)\n", minAgeRows[0].Age, minAgeRows[0].Name)
}
// 最大分数
maxScoreRows, _ := empTbl.OrderBy("Score", true).Limit(1).Find()
if len(maxScoreRows) > 0 {
fmt.Printf("最高分数: %d分 (%s)\n", maxScoreRows[0].Score, maxScoreRows[0].Name)
}
// 计算平均分数
allEmps, _ := empTbl.Find()
var totalScore int64
for _, emp := range allEmps {
totalScore += emp.Score
}
avgScore := float64(totalScore) / float64(len(allEmps))
fmt.Printf("平均分数: %.2f\n", avgScore)
// 各部门平均分
deptMap := make(map[string][]int64)
for _, emp := range allEmps {
deptMap[emp.Dept] = append(deptMap[emp.Dept], emp.Score)
}
for dept, scores := range deptMap {
var sum int64
for _, s := range scores {
sum += s
}
avg := float64(sum) / float64(len(scores))
fmt.Printf(" %s: 平均 %.2f 分 (%d 人)\n", dept, avg, len(scores))
}
// 查询某员工的所有订单
employeeID := int64(1)
orders, _ := orderTbl.Where("EmployeeID", "=", employeeID).Find()
fmt.Printf("员工 %d 的订单数: %d\n", employeeID, len(orders))
for _, order := range orders {
fmt.Printf(" 订单ID=%d, 金额=%d, 状态=%d\n", order.ID, order.Amount, order.Status)
}
// 查询每个员工的订单总数
emps, _ := empTbl.Find()
for _, emp := range emps[:10] { // 只看前10名员工
orders, _ := orderTbl.Where("EmployeeID", "=", int64(emp.ID)).Find()
fmt.Printf("%-15s: %d 个订单\n", emp.Name, len(orders))
}
// 查询工程部员工的状态为"已完成"的订单
deptEmps, _ := empTbl.Where("Dept", "=", "工程部").Find()
var totalAmount int64
var orderCount int
for _, emp := range deptEmps {
orders, _ := orderTbl.
Where("EmployeeID", "=", int64(emp.ID)).
Where("Status", "=", int64(1)). // 1 = done
Find()
for _, order := range orders {
totalAmount += order.Amount
orderCount++
}
}
fmt.Printf("工程部已完成订单: %d 笔, 总金额: %d\n", orderCount, totalAmount)
// 禁用自动提交
db.SetAutoCommitDelay(0)
// 执行多个操作
empTbl.Insert(&Employee{Name: "A", Age: 25, Score: 90, Dept: "IT"})
empTbl.Insert(&Employee{Name: "B", Age: 30, Score: 85, Dept: "HR"})
empTbl.Delete(5)
// 一次性提交
if err := db.Commit(); err != nil {
fmt.Printf("提交失败: %v\n", err)
// 可以回滚或重试
} else {
fmt.Println("✅ 事务提交成功")
}
// 设置 500ms 防抖
db.SetAutoCommitDelay(500 * time.Millisecond)
// 连续插入,最后一次操作后 500ms 自动 Commit
for i := 1; i <= 100; i++ {
empTbl.Insert(&Employee{...})
}
// 等待自动提交
time.Sleep(1 * time.Second)
fmt.Println("数据已自动提交")
// 当脏页超过 2000 页时自动触发 Commit
db.SetDirtyThreshold(2000)
// 大量插入时会自动分批 Commit
for i := 1; i <= 100000; i++ {
empTbl.Insert(&Employee{...})
}
// 无需手动 Commit,系统会根据脏页阈值自动提交
// 即使忘记 Commit,Close 时也会自动提交
db, _ := DB.Open("test.db")
tbl, _ := DB.UseTable[Employee](db, "test")
for i := 1; i <= 1000; i++ {
tbl.Insert(&Employee{...})
}
// 没有手动 Commit
db.Close() // ✅ Close 内部会调用 Commit,确保数据持久化
// 重新打开验证
db2, _ := DB.Open("test.db")
tbl2, _ := DB.UseTable[Employee](db2, "test")
count, _ := tbl2.Count()
fmt.Printf("Close 后数据保留: %d 条\n", count) // 输出: 1000 条
// V1: 初始版本
type EmployeeV1 struct {
DB.BaseModel
Name string `tsdb:"32byte"`
Age int64 `tsdb:"8byte"`
}
// V2: 添加新字段
type EmployeeV2 struct {
DB.BaseModel
Name string `tsdb:"32byte"`
Age int64 `tsdb:"8byte"`
Email string `tsdb:"64byte"` // 新增字段
}
// TsDB2 自动处理 schema 版本迁移
tbl, _ := DB.UseTable[EmployeeV2](db, "employee")
// 标记字段为 dropped(不物理删除,保持兼容性)
empCore.DropField("Score") // Score 字段标记为已删除
// 查询时不再返回该字段
emp, _ := tbl.Find(1)
// emp.Score 将为默认值 0
// 删除整个表(回收所有页)
err := db.DropTable("order")
if err != nil {
fmt.Printf("删除表失败: %v\n", err)
}
// 验证删除
_, exists := db.CoreDB().FindTable("order")
if !exists {
fmt.Println("✅ order 表已删除")
}
// 查看所有索引
table, _ := db.CoreDB().FindTable("employee")
for _, idx := range table.GetIndexes() {
fmt.Printf("索引: %s, 类型: %d, 根页: %d\n",
idx.Name, idx.Type, idx.EntryPage)
}
// 删除索引
table.DropIndex("idx_age")
// 统计信息
fi, _ := os.Stat("mydb.db")
fmt.Printf("数据库大小: %.2f MB\n", float64(fi.Size())/1024/1024)
// 表统计
count, _ := empTbl.Count()
fmt.Printf("员工表行数: %d\n", count)
// BufferPool 统计
bp := db.CoreDB().GetBufferPool()
fmt.Printf("缓存页数: %d\n", bp.Len())
fmt.Printf("脏页数: %d\n", bp.DirtyCount())
// TsDB2 不是线程安全的,需要在应用层加锁
var mu sync.Mutex
go func() {
mu.Lock()
defer mu.Unlock()
empTbl.Insert(&Employee{...})
}()
go func() {
mu.Lock()
defer mu.Unlock()
empTbl.Find(1)
}()
package main
import (
"TsDB2/DB"
"fmt"
"time"
)
type Employee struct {
DB.BaseModel
Name string `tsdb:"32byte"`
Age int64 `tsdb:"8byte"`
Score int64 `tsdb:"8byte"`
Dept string `tsdb:"16byte"`
}
func main() {
// 1. 打开数据库
db, _ := DB.Open("company.db")
defer db.Close()
db.SetAutoCommitDelay(0) // 手动控制
// 2. 建表 + 索引(自动推导表名)
tbl, _ := DB.UseTable[Employee](db) // ✅ 无需传递 "employee"
core, _ := db.CoreDB().FindTable("employee")
core.CreateIndex("idx_age", page.IndexTypeBTree, []byte{2})
core.CreateIndex("idx_dept", page.IndexTypeBTree, []byte{4})
// 3. 批量插入
fmt.Println("插入数据...")
depts := []string{"工程部", "销售部", "人事部", "财务部", "运维部"}
for i := 1; i <= 1000; i++ {
tbl.Insert(&Employee{
Name: fmt.Sprintf("Emp%04d", i),
Age: int64(20 + (i % 50)),
Score: int64(50 + (i % 51)),
Dept: depts[i%5],
})
}
db.Commit()
// 4. 查询
fmt.Println("\n=== 查询示例 ===")
// 4.1 主键查询
emp, _ := tbl.Find(1)
fmt.Printf("ID=1: %s, %d岁\n", emp.Name, emp.Age)
// 4.2 条件查询
young, _ := tbl.Where("Age", "<", int64(25)).Find()
fmt.Printf("25岁以下: %d 人\n", len(young))
// 4.3 排序 + 分页
top10, _ := tbl.OrderBy("Score", true).Limit(10).Find()
fmt.Println("分数Top 10:")
for i, e := range top10 {
fmt.Printf(" [%d] %s: %d分\n", i+1, e.Name, e.Score)
}
// 4.4 聚合
total, _ := tbl.Count()
fmt.Printf("总人数: %d\n", total)
// 5. 更新
fmt.Println("\n=== 更新示例 ===")
tbl.Update(&Employee{
BaseModel: DB.BaseModel{ID: 1},
Score: 100,
})
emp, _ = tbl.Find(1)
fmt.Printf("ID=1 更新后分数: %d\n", emp.Score)
// 6. 删除
fmt.Println("\n=== 删除示例 ===")
tbl.Delete(2)
_, err := tbl.Find(2)
if err != nil {
fmt.Println("ID=2 已删除")
}
// 7. 复杂查询
fmt.Println("\n=== 复杂查询 ===")
itHighScore, _ := tbl.
Where("Dept", "=", "工程部").
Where("Score", ">", int64(80)).
Find()
fmt.Printf("工程部高分员工: %d 人\n", len(itHighScore))
fmt.Println("\n✅ 所有操作完成!")
}
祝使用愉快! 🎉