Переглянути джерело

feat: UseTable 自动推导表名,无需手动传递

优化前: DB.UseTable[Employee](db, employee)  // 冗余
优化后: DB.UseTable[Employee](db)              // ✅ 自动推导

实现原理:
- 通过 reflect.TypeOf 获取类型名
- Employee -> employee (首字母小写)
- OrderItem -> orderItem

向后兼容:
- 仍支持手动指定表名: UseTable[T](db, custom_name)
- 所有现有代码无需修改
yl32940 1 місяць тому
батько
коміт
010d70b1eb
3 змінених файлів з 918 додано та 7 видалено
  1. 32 7
      DB/db.go
  2. 886 0
      docs/OPERATION_TUTORIAL.md
  3. BIN
      no_commit_test.db

+ 32 - 7
DB/db.go

@@ -4,6 +4,8 @@ import (
 	"TsDB2/DB/core"
 	"TsDB2/DB/core/types"
 	"fmt"
+	"reflect"
+	"strings"
 	"time"
 )
 
@@ -51,26 +53,38 @@ func (db *DB) DebugTableState(tableName string) {
 // UseTable 获取或创建泛型表
 // 如果表不存在,会自动创建表和索引
 // 如果表已存在,会自动同步 schema:struct 多的字段自动添加,少的字段自动删除
-func UseTable[T any](db *DB, name string) (*Table[T], error) {
+//
+// 用法1: 自动推导表名(推荐)
+//   tbl, _ := DB.UseTable[Employee](db)  // 表名自动为 "employee"
+//
+// 用法2: 手动指定表名
+//   tbl, _ := DB.UseTable[Employee](db, "emp_table")  // 自定义表名
+func UseTable[T any](db *DB, name ...string) (*Table[T], error) {
 	var zero T
 	model, err := ParseModel(&zero)
 	if err != nil {
 		return nil, fmt.Errorf("tsdb: parse model: %w", err)
 	}
 
+	// 自动推导表名:从类型名转为小写(如 Employee -> employee)
+	tableName := typeNameToTableName(zero)
+	if len(name) > 0 && name[0] != "" {
+		tableName = name[0]  // 用户指定的表名优先
+	}
+
 	// 尝试查找已有表
-	coreTbl, ok := db.coreDB.FindTable(name)
+	coreTbl, ok := db.coreDB.FindTable(tableName)
 	if !ok {
 		// 表不存在,创建新表
-		coreTbl, err = db.coreDB.CreateTable(name, model.CoreFields)
+		coreTbl, err = db.coreDB.CreateTable(tableName, model.CoreFields)
 		if err != nil {
-			return nil, fmt.Errorf("tsdb: create table %s: %w", name, err)
+			return nil, fmt.Errorf("tsdb: create table %s: %w", tableName, err)
 		}
 		// 创建一级索引
-		idxName := "pk_" + name
+		idxName := "pk_" + tableName
 		_, err = coreTbl.CreateIndex(idxName, model.GetIndexType(), []byte{model.CorePKField})
 		if err != nil {
-			return nil, fmt.Errorf("tsdb: create index for %s: %w", name, err)
+			return nil, fmt.Errorf("tsdb: create index for %s: %w", tableName, err)
 		}
 	} else {
 		// 表已存在,自动同步 schema
@@ -80,7 +94,7 @@ func UseTable[T any](db *DB, name string) (*Table[T], error) {
 	tbl := &Table[T]{
 		coreTable: coreTbl,
 		model:     model,
-		name:      name,
+		name:      tableName,
 	}
 	tbl.refreshActiveColumns()
 	return tbl, nil
@@ -135,3 +149,14 @@ func (db *DB) DropTable(name string) error {
 func (db *DB) CoreDB() *core.DB {
 	return db.coreDB
 }
+
+// typeNameToTableName 从类型名推导表名(Employee -> employee)
+func typeNameToTableName(v any) string {
+	t := reflect.TypeOf(v)
+	name := t.Name()
+	if name == "" {
+		return "table"
+	}
+	// 首字母小写:Employee -> employee, OrderItem -> orderItem
+	return strings.ToLower(name[:1]) + name[1:]
+}

+ 886 - 0
docs/OPERATION_TUTORIAL.md

@@ -0,0 +1,886 @@
+# TsDB2 完整操作教程
+
+本教程涵盖 TsDB2 时序数据库的所有核心操作,包括建表、增删改查、条件查询、索引管理、事务控制等。
+
+---
+
+## 📋 目录
+
+1. [基础概念](#1-基础概念)
+2. [建表与索引](#2-建表与索引)
+3. [插入数据 (Create)](#3-插入数据-create)
+4. [查询数据 (Read)](#4-查询数据-read)
+5. [更新数据 (Update)](#5-更新数据-update)
+6. [删除数据 (Delete)](#6-删除数据-delete)
+7. [条件查询详解](#7-条件查询详解)
+8. [排序与分页](#8-排序与分页)
+9. [聚合查询](#9-聚合查询)
+10. [多表关联](#10-多表关联)
+11. [事务与提交](#11-事务与提交)
+12. [高级特性](#12-高级特性)
+
+---
+
+## 1. 基础概念
+
+### 1.1 数据模型定义
+
+TsDB2 使用 Go struct 定义数据模型,通过 `tsdb` tag 指定字段类型:
+
+```go
+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 / uint64
+- `4byte`: int32 / uint32
+- `2byte`: int16 / uint16
+- `1byte`: int8 / uint8
+
+### 1.2 打开数据库
+
+```go
+// 打开或创建数据库文件
+db, err := DB.Open("mydb.db")
+if err != nil {
+    panic(err)
+}
+defer db.Close()  // 程序退出前关闭
+
+// 设置自动提交延迟(防抖)
+db.SetAutoCommitDelay(500 * time.Millisecond)  // 500ms 后自动 Commit
+```
+
+---
+
+## 2. 建表与索引
+
+### 2.1 创建表
+
+```go
+// ✅ 推荐方式:自动推导表名(从类型名 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")` → 使用自定义表名
+
+### 2.2 创建索引
+
+TsDB2 支持多种索引类型:
+
+```go
+// 获取表的底层 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): 复合索引,多字段联合索引
+
+---
+
+## 3. 插入数据 (Create)
+
+### 3.1 单行插入
+
+```go
+err := empTbl.Insert(&Employee{
+    Name:  "张三",
+    Age:   25,
+    Score: 95,
+    Dept:  "工程部",
+})
+if err != nil {
+    fmt.Printf("插入失败: %v\n", err)
+}
+```
+
+### 3.2 批量插入
+
+```go
+// 插入 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)
+    }
+}
+```
+
+### 3.3 性能优化:批量 Commit
+
+```go
+// 禁用自动提交,手动控制 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())
+```
+
+**性能对比:**
+- 每行自动 Commit: 10万行约 100秒
+- 批量 Commit: 10万行约 4秒(**快 25 倍**)
+
+---
+
+## 4. 查询数据 (Read)
+
+### 4.1 主键精确查询
+
+```go
+// 根据 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)
+}
+```
+
+### 4.2 条件查询
+
+```go
+// 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)
+}
+```
+
+### 4.3 遍历所有记录
+
+```go
+// 全表扫描
+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)
+    }
+}
+```
+
+---
+
+## 5. 更新数据 (Update)
+
+### 5.1 根据主键更新
+
+```go
+// 更新 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
+```
+
+### 5.2 批量更新(循环)
+
+```go
+// 给所有工程部员工加 10 分
+emps, _ := empTbl.Where("Dept", "=", "工程部").Find()
+for _, emp := range emps {
+    emp.Score += 10
+    empTbl.Update(emp)
+}
+fmt.Printf("已为 %d 名工程部员工加分\n", len(emps))
+```
+
+---
+
+## 6. 删除数据 (Delete)
+
+### 6.1 根据主键删除
+
+```go
+// 删除 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 已成功删除")
+}
+```
+
+### 6.2 批量删除(循环)
+
+```go
+// 删除所有分数低于 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)
+```
+
+### 6.3 级联删除
+
+```go
+// 删除部门时,同时删除该部门所有员工
+deptToDelete := "临时工"
+emps, _ := empTbl.Where("Dept", "=", deptToDelete).Find()
+for _, emp := range emps {
+    empTbl.Delete(emp.ID)
+}
+fmt.Printf("已删除 %d 名 %s 员工\n", len(emps), deptToDelete)
+```
+
+---
+
+## 7. 条件查询详解
+
+### 7.1 比较运算符
+
+```go
+// 等于 (=)
+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()
+```
+
+### 7.2 范围查询
+
+```go
+// 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))
+```
+
+### 7.3 IN 查询
+
+```go
+// WHERE Dept IN ("工程部", "技术部")
+rows, _ := empTbl.Where("Dept", "in", []string{"工程部", "技术部"}).Find()
+fmt.Printf("工程/技术部员工: %d 人\n", len(rows))
+```
+
+### 7.4 LIKE 模糊查询
+
+```go
+// 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))
+```
+
+### 7.5 多条件组合
+
+```go
+// 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))
+```
+
+### 7.6 OR 条件
+
+```go
+// 使用 OrCondition
+import "TsDB2/DB/core"
+
+cond := core.OrCondition{
+    core.EqCondition{Field: "Dept", Value: "工程部"},
+    core.EqCondition{Field: "Dept", Value: "技术部"},
+}
+rows, _ := empTbl.WhereCondition(cond).Find()
+```
+
+---
+
+## 8. 排序与分页
+
+### 8.1 升序排序
+
+```go
+// 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)
+}
+```
+
+### 8.2 降序排序
+
+```go
+// 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)
+}
+```
+
+### 8.3 LIMIT 限制数量
+
+```go
+// 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)
+}
+```
+
+### 8.4 OFFSET + LIMIT 分页
+
+```go
+// 每页 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))
+```
+
+### 8.5 完整分页示例
+
+```go
+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)
+}
+```
+
+---
+
+## 9. 聚合查询
+
+### 9.1 COUNT 计数
+
+```go
+// 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)
+```
+
+### 9.2 MIN/MAX(通过排序实现)
+
+```go
+// 最小年龄
+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)
+}
+```
+
+### 9.3 SUM/AVG(循环计算)
+
+```go
+// 计算平均分数
+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))
+}
+```
+
+---
+
+## 10. 多表关联
+
+### 10.1 简单关联查询
+
+```go
+// 查询某员工的所有订单
+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)
+}
+```
+
+### 10.2 嵌套循环关联
+
+```go
+// 查询每个员工的订单总数
+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))
+}
+```
+
+### 10.3 复杂关联 + 条件
+
+```go
+// 查询工程部员工的状态为"已完成"的订单
+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)
+```
+
+---
+
+## 11. 事务与提交
+
+### 11.1 手动 Commit
+
+```go
+// 禁用自动提交
+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("✅ 事务提交成功")
+}
+```
+
+### 11.2 防抖自动提交
+
+```go
+// 设置 500ms 防抖
+db.SetAutoCommitDelay(500 * time.Millisecond)
+
+// 连续插入,最后一次操作后 500ms 自动 Commit
+for i := 1; i <= 100; i++ {
+    empTbl.Insert(&Employee{...})
+}
+
+// 等待自动提交
+time.Sleep(1 * time.Second)
+fmt.Println("数据已自动提交")
+```
+
+### 11.3 脏页阈值自动提交
+
+```go
+// 当脏页超过 2000 页时自动触发 Commit
+db.SetDirtyThreshold(2000)
+
+// 大量插入时会自动分批 Commit
+for i := 1; i <= 100000; i++ {
+    empTbl.Insert(&Employee{...})
+}
+// 无需手动 Commit,系统会根据脏页阈值自动提交
+```
+
+### 11.4 Close 兜底提交
+
+```go
+// 即使忘记 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 条
+```
+
+---
+
+## 12. 高级特性
+
+### 12.1 Schema 演进(添加字段)
+
+```go
+// 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")
+```
+
+### 12.2 删除字段(软删除)
+
+```go
+// 标记字段为 dropped(不物理删除,保持兼容性)
+empCore.DropField("Score")  // Score 字段标记为已删除
+
+// 查询时不再返回该字段
+emp, _ := tbl.Find(1)
+// emp.Score 将为默认值 0
+```
+
+### 12.3 删除表
+
+```go
+// 删除整个表(回收所有页)
+err := db.DropTable("order")
+if err != nil {
+    fmt.Printf("删除表失败: %v\n", err)
+}
+
+// 验证删除
+_, exists := db.CoreDB().FindTable("order")
+if !exists {
+    fmt.Println("✅ order 表已删除")
+}
+```
+
+### 12.4 索引管理
+
+```go
+// 查看所有索引
+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")
+```
+
+### 12.5 性能监控
+
+```go
+// 统计信息
+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())
+```
+
+### 12.6 并发安全
+
+```go
+// 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)
+}()
+```
+
+---
+
+## 🎯 完整示例:员工管理系统
+
+```go
+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✅ 所有操作完成!")
+}
+```
+
+---
+
+## 📚 参考资料
+
+- **Analyzer 工具**: 可视化查看数据库内部结构
+- **full_test**: 完整功能测试用例
+- **no_commit_test**: 事务与自动提交流程测试
+
+---
+
+**祝使用愉快!** 🎉

BIN
no_commit_test.db