第 5 章:添加操作


5.1 完整的可运行示例

让我们通过一个完整的示例来演示 sfsDb 的添加操作:

package main

import (
	"fmt"
	"os"

	"github.com/liaoran123/sfsDb/engine"
	"github.com/liaoran123/sfsDb/storage"
)

func main() {
	fmt.Println("=== sfsDb 数据库实战 - 第 4 章:添加操作示例 ===")
	fmt.Println()

	dbPath := "./bible_examples_chapter04_db"
	cleanup(dbPath)

	fmt.Println("1. 初始化数据库")
	_, err := storage.GetDBManager().OpenDB(dbPath)
	if err != nil {
		fmt.Printf("数据库打开失败: %v\n", err)
		return
	}
	defer storage.GetDBManager().CloseDB()
	fmt.Println("   ✓ 数据库打开成功")
	fmt.Println()

	fmt.Println("2. 创建表并设置字段")
	table, err := engine.NewTable("users")
	if err != nil {
		fmt.Printf("创建表失败: %v\n", err)
		return
	}

	fields := map[string]any{
		"id":    0,
		"name":  "",
		"email": "",
		"age":   0,
	}
	err = table.SetFields(fields)
	if err != nil {
		fmt.Printf("设置字段失败: %v\n", err)
		return
	}

	primaryKey, err := engine.NewDefaultPrimaryKey("pk_id")
	primaryKey.AddFields("id")
	table.CreateIndex(primaryKey)
	fmt.Println("   ✓ 表创建成功")
	fmt.Println()

	fmt.Println("3. 单个插入操作 (Insert)")
	user1 := map[string]any{"id": 1, "name": "张三", "email": "zhangsan@example.com", "age": 28}
	id1, err := table.Insert(&user1)
	if err != nil {
		fmt.Printf("插入数据失败: %v\n", err)
		return
	}
	fmt.Printf("   ✓ 成功插入用户,ID: %d\n", id1)
	fmt.Println()

	fmt.Println("4. 批量插入操作 (BatchInsertInc)")
	users := []*map[string]any{
		{"id": 2, "name": "李四", "email": "lisi@example.com", "age": 32},
		{"id": 3, "name": "王五", "email": "wangwu@example.com", "age": 25},
		{"id": 4, "name": "赵六", "email": "zhaoliu@example.com", "age": 35},
	}
	ids, err := table.BatchInsertInc(users)
	if err != nil {
		fmt.Printf("批量插入失败: %v\n", err)
		return
	}
	fmt.Printf("   ✓ 成功批量插入 %d 个用户,IDs: %v\n", len(ids), ids)
	fmt.Println()

	fmt.Println("5. 批量插入操作 (BatchInsertNoInc)")
	usersNoInc := []*map[string]any{
		{"id": 5, "name": "孙七", "email": "sunqi@example.com", "age": 29},
		{"id": 6, "name": "周八", "email": "zhouba@example.com", "age": 31},
	}
	idsNoInc, err := table.BatchInsertNoInc(usersNoInc)
	if err != nil {
		fmt.Printf("批量插入失败: %v\n", err)
		return
	}
	fmt.Printf("   ✓ 成功批量插入 %d 个用户,IDs: %v\n", len(idsNoInc), idsNoInc)
	fmt.Println()

	fmt.Println("6. 验证所有数据")
	searchAll := map[string]any{"id": nil}
	dataIter, _ := table.Search(&searchAll)
	defer dataIter.Release()

	records := dataIter.GetRecords(true)
	defer records.Release()

	fmt.Println("   所有用户列表:")
	for _, user := range records {
		fmt.Printf("   - ID: %v, 姓名: %v, 邮箱: %v, 年龄: %v\n",
			user["id"], user["name"], user["email"], user["age"])
	}
	fmt.Println()

	fmt.Println("=== 添加操作演示完成!===")
}

func cleanup(path string) {
	os.RemoveAll(path)
}

5.2 Insert 方法

Insert 方法用于插入单条记录到表中。

函数签名(来自 engine/tableInsert.go):

func (t *Table) Insert(fields *map[string]any, batchs ...storage.Batch) (currentID int, err error) {
    // 实现代码...
}

参数说明

  • fields:要插入的字段映射
  • batchs:可选的批处理对象

返回值

  • currentID:插入记录的 ID
  • err:错误信息

使用示例

// 插入单条记录
user := map[string]any{"id": 1, "name": "张三", "email": "zhangsan@example.com"}
id, err := table.Insert(&user)
if err != nil {
    fmt.Printf("插入失败: %v\n", err)
} else {
    fmt.Printf("插入成功,ID: %d\n", id)
}

5.3 BatchInsertInc 方法

BatchInsertInc 方法用于批量插入记录,支持自动递增 ID。

函数签名(来自 engine/tableInsert.go):

func (t *Table) BatchInsertInc(records []*map[string]any, batchs ...storage.Batch) ([]int, error) {
    // 实现代码...
}

参数说明

  • records:要插入的记录数组
  • batchs:可选的批处理对象

返回值

  • []int:插入记录的 ID 数组
  • error:错误信息

使用示例

// 批量插入记录
users := []*map[string]any{
    {"name": "李四", "email": "lisi@example.com"},
    {"name": "王五", "email": "wangwu@example.com"},
}
ids, err := table.BatchInsertInc(users)
if err != nil {
    fmt.Printf("批量插入失败: %v\n", err)
} else {
    fmt.Printf("批量插入成功,IDs: %v\n", ids)
}

5.4 BatchInsertNoInc 方法

BatchInsertNoInc 方法用于批量插入记录,不自动递增 ID(使用用户提供的 ID)。

函数签名(来自 engine/tableInsert.go):

func (t *Table) BatchInsertNoInc(records []*map[string]any, batchs ...storage.Batch) ([]int, error) {
    // 实现代码...
}

参数说明

  • records:要插入的记录数组(必须包含 ID 字段)
  • batchs:可选的批处理对象

返回值

  • []int:插入记录的 ID 数组
  • error:错误信息

使用示例

// 批量插入记录(使用指定的 ID)
users := []*map[string]any{
    {"id": 101, "name": "孙七", "email": "sunqi@example.com"},
    {"id": 102, "name": "周八", "email": "zhouba@example.com"},
}
ids, err := table.BatchInsertNoInc(users)
if err != nil {
    fmt.Printf("批量插入失败: %v\n", err)
} else {
    fmt.Printf("批量插入成功,IDs: %v\n", ids)
}

5.5 插入操作的内部实现

5.5.1 核心流程

  1. 参数验证:检查表是否初始化、字段是否设置
  2. ID 处理:处理自动递增 ID 或使用用户提供的 ID
  3. 数据编码:将字段数据编码为二进制格式
  4. 索引处理:更新主键索引和其他索引
  5. 数据存储:将数据存储到 KV 存储中
  6. 批量处理:支持批处理操作以提高性能

5.5.2 关键代码

ID 生成逻辑

// 生成 ID
if (*fields)[t.PrimaryKeyName] == nil {
    // 自动递增 ID
    currentID = t.currentID
    t.currentID++
} else {
    // 使用用户提供的 ID
    currentID = (*fields)[t.PrimaryKeyName].(int)
    if currentID >= t.currentID {
        t.currentID = currentID + 1
    }
}

数据编码

// 编码数据
value, err := t.encodeFields(*fields)
if err != nil {
    return 0, err
}

// 生成键
key := index.JoinFullValues(fieldsBytes, currentID)
defer key.Release()

5.6 插入操作的最佳实践

  1. 批量插入:对于大量数据,使用 BatchInsertIncBatchInsertNoInc 以提高性能
  2. ID 管理:根据业务需求选择自动递增 ID 或自定义 ID
  3. 错误处理:始终检查插入操作的错误返回
  4. 事务处理:对于重要操作,考虑使用事务确保数据一致性
  5. 数据验证:在插入前验证数据的有效性

5.7 性能优化

  • 批处理:使用批处理减少数据库交互次数
  • 预分配:预分配切片空间以减少内存分配
  • 索引设计:合理设计索引以提高插入性能
  • 并发插入:在适当情况下使用并发插入

5.8 小结

本章我们通过项目的实际代码学习了 sfsDb 的添加操作:

  • 单条插入:使用 Insert 方法插入单条记录
  • 批量插入:使用 BatchInsertIncBatchInsertNoInc 方法批量插入记录
  • ID 管理:支持自动递增 ID 和自定义 ID
  • 批处理支持:支持批处理操作以提高性能
  • 内部实现:了解插入操作的核心流程和关键代码
  • 最佳实践:掌握插入操作的最佳实践和性能优化技巧

在下一章中,我们将学习删除操作。


本书版本:6.0.0
最后更新:2026-03-16
sfsDb - 以工业物联网边缘计算为核心场景的高性能嵌入式数据库!🚀
技术栈 - Go、leveldb。纯golang实现。
项目地址GitHub
GitCode 镜像GitCode

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐