# sqlkv
**Repository Path**: MM-Q/sqlkv
## Basic Information
- **Project Name**: sqlkv
- **Description**: No description available
- **Primary Language**: Go
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-04
- **Last Updated**: 2026-08-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 🗄️ sqlkv
**基于 SQLite 模拟 Redis 设计的轻量级键值库(纯 Go、零 CGO)**
[](https://go.dev/) [](./LICENSE) [](https://gitee.com/MM-Q/sqlkv) [](./go.mod) [](https://www.sqlite.org/) [](https://gitee.com/MM-Q/sqlkv)
[仓库地址](https://gitee.com/MM-Q/sqlkv) · [功能特性](#-核心特性) · [快速开始](#-快速开始) · [API 文档](#-api-文档概述) · [许可证](#-许可证)
---
## 📖 项目简介
**sqlkv** 是一个基于 **SQLite** 模拟 **Redis** 使用体验的轻量级键值库。它保留了 Redis 简洁的 API 风格(`Set` / `Get` / `Del` / `Select` 切换 16 个逻辑库等),底层由 SQLite 提供持久化、事务与并发保证。
使用纯 Go 实现(基于 `modernc.org/sqlite`),**无 CGO 依赖**,交叉编译简单、部署零成本——非常适合作为嵌入式存储、配置中心、小型缓存或数据迁移的中间格式。
```
┌─────────────────────────────────────────────┐
│ sqlkv (Redis 风格 API) │
├─────────────────────────────────────────────┤
│ Set · Get · Del · Exists · Keys · ForEach │
│ SetNX · SetMany · GetMany · Count │
│ Select(0~15) · FlushDB · FlushAll │
│ SetJSON/GetJSON · SetString/GetString │
│ Dump · Load · Backup · Vacuum · DBSize │
├─────────────────────────────────────────────┤
│ SQLite (modernc.org/sqlite) │
│ WAL · 预编译语句 · 连接池 · 事务 │
└─────────────────────────────────────────────┘
```
---
## ✨ 核心特性
- 🚀 **纯 Go、零 CGO**:基于 `modernc.org/sqlite`,跨平台交叉编译无障碍,无需 C 工具链
- 🔑 **Redis 风格 API**:`Select` 切换 0~15 共 16 个逻辑库,语义贴近 Redis
- ⚡ **高性能优化**:预编译语句(Statement Cache)、UPSERT 写入、WAL 模式、连接池多路复用
- 💾 **持久化**:数据落盘 SQLite 单文件,天然具备事务与崩溃恢复能力
- 🔒 **并发安全**:多连接读写并发安全(`-race` 检测通过),多进程写冲突自动等待
- 🧩 **JSON 原生支持**:`SetJSON` / `GetJSON` 直接存取任意结构体
- 📦 **批量操作**:`SetMany` / `GetMany` 事务化批量读写
- 🗂️ **流式导入导出**:`Dump` / `DumpTo` / `Load` / `LoadFrom` 支持任意大小数据的流式迁移
- 🛠️ **运维能力**:`Backup`(一致性快照)、`Vacuum`(空间回收)、`DBSize`(容量统计)
- 🎯 **错误语义清晰**:内置 `ErrKeyNotFound` 等 sentinel error,配合 `errors.Is` 精确判断
---
## 📦 安装指南
### 环境要求
| 要求 | 说明 |
|------|------|
| Go 版本 | **1.26.4** 或更高 |
| 操作系统 | Windows / Linux / macOS(纯 Go,无平台限制) |
| 依赖 | 无 CGO,仅需 `modernc.org/sqlite` |
### 安装
在你的项目目录中执行:
```bash
go get gitee.com/MM-Q/sqlkv
```
> 💡 仓库地址:[https://gitee.com/MM-Q/sqlkv.git](https://gitee.com/MM-Q/sqlkv.git)
---
## 🚀 快速开始
### 基础用法
```go
package main
import (
"fmt"
"log"
kvstore "gitee.com/MM-Q/sqlkv"
)
func main() {
// 打开数据库(不存在则自动创建,默认切换到 DB 0)
kv, err := kvstore.New("data.db")
if err != nil {
log.Fatal(err)
}
defer kv.Close()
// 写入与读取
if err := kv.Set("name", []byte("sqlkv")); err != nil {
log.Fatal(err)
}
val, err := kv.Get("name")
if err != nil {
log.Fatal(err)
}
fmt.Printf("name = %s\n", val) // name = sqlkv
// 判断键是否存在
if kv.Exists("name") {
fmt.Println("key 'name' 存在")
}
// 删除与计数
_ = kv.Del("name")
cnt, _ := kv.Count()
fmt.Printf("剩余键数: %d\n", cnt)
}
```
### 高级用法
**多逻辑库隔离**
```go
// 切换 16 个逻辑库之一(0~15),各库数据完全隔离
_ = kv.Select(1)
_ = kv.Set("k", []byte("db1"))
_ = kv.Select(2)
_ = kv.Set("k", []byte("db2"))
_ = kv.Select(1)
v, _ := kv.Get("k") // "db1" — 不互相干扰
```
**分布式锁(SetNX)**
```go
// 仅当键不存在时写入,成功返回 true —— 天然适合做分布式锁
locked, err := kv.SetNX("lock:order:1001", []byte("holder"))
if err != nil {
log.Fatal(err)
}
if locked {
defer kv.Del("lock:order:1001")
// 临界区逻辑...
}
```
**批量读写(单事务)**
```go
items := map[string][]byte{
"a": []byte("1"),
"b": []byte("2"),
"c": []byte("3"),
}
if err := kv.SetMany(items); err != nil { // 全部成功或全部回滚
log.Fatal(err)
}
got, _ := kv.GetMany("a", "b", "c", "missing") // 缺失的键不会出现在结果中
fmt.Println(string(got["b"])) // "2"
```
**结构化数据(JSON)**
```go
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
_ = kv.SetJSON("user:1", User{Name: "张三", Age: 30})
var u User
if err := kv.GetJSON("user:1", &u); err != nil {
log.Fatal(err)
}
fmt.Printf("%s, %d 岁\n", u.Name, u.Age)
```
**遍历与迭代**
```go
// 按键升序遍历当前库全部键值,回调返回错误即中止
_ = kv.ForEach(func(key string, value []byte) error {
fmt.Printf("%s = %s\n", key, value)
return nil
})
// 列出全部键
keys, _ := kv.Keys()
fmt.Println(keys)
```
**备份与迁移**
```go
// 一致性快照备份(等效 sqlite3 .backup)
_ = kv.Backup("backup.db")
// 导出全部数据为 JSON,可导入任意新库
data, _ := kv.Dump()
_ = data // []byte
// 从 JSON 恢复(合并语义:覆盖已有键、保留无关键)
_ = kv.Load(data)
```
---
## 📚 API 文档概述
### 基础操作
| 方法 | 签名 | 说明 |
|------|------|------|
| `New` | `New(path string) (*KVStore, error)` | 打开数据库,自动建表,默认 DB 0 |
| `Close` | `Close() error` | 关闭预编译语句并关闭数据库 |
| `Select` | `Select(db int) error` | 切换 DB(0~15),越界返回 `ErrInvalidDBIndex` |
| `Set` | `Set(key string, value []byte) error` | 写入键值(UPSERT,已存在则覆盖) |
| `Get` | `Get(key string) ([]byte, error)` | 读取键值,缺失返回 `ErrKeyNotFound` |
| `Del` | `Del(key string) error` | 删除键(不存在不报错) |
| `Exists` | `Exists(key string) bool` | 判断键是否存在 |
| `Count` | `Count() (int, error)` | 当前 DB 键总数 |
| `Keys` | `Keys() ([]string, error)` | 列出当前 DB 全部键(升序) |
### 批量与迭代
| 方法 | 签名 | 说明 |
|------|------|------|
| `SetMany` | `SetMany(items map[string][]byte) error` | 单事务批量写入,失败整体回滚 |
| `GetMany` | `GetMany(keys ...string) (map[string][]byte, error)` | 批量读取,缺失键不出现在结果中 |
| `SetNX` | `SetNX(key string, value []byte) (bool, error)` | 键不存在才写入(可用于分布式锁) |
| `ForEach` | `ForEach(fn func(key, value []byte) error) error` | 升序遍历当前库,回调报错即中止 |
### 便捷方法
| 方法 | 签名 | 说明 |
|------|------|------|
| `SetString` | `SetString(key, value string) error` | 字符串形式写入 |
| `GetString` | `GetString(key string) (string, error)` | 字符串形式读取 |
| `SetJSON` | `SetJSON(key string, v any) error` | 序列化任意值为 JSON 后写入 |
| `GetJSON` | `GetJSON(key string, out any) error` | 读取并反序列化 JSON(out 需为指针) |
### 运维管理
| 方法 | 签名 | 说明 |
|------|------|------|
| `FlushDB` | `FlushDB() error` | 清空当前 DB 全部键 |
| `FlushAll` | `FlushAll() error` | 清空全部 16 个 DB |
| `Dump` | `Dump() ([]byte, error)` | 导出全部数据为 JSON |
| `DumpTo` | `DumpTo(w io.Writer) error` | 流式导出(内存占用恒定) |
| `Load` | `Load(data []byte) error` | 从 JSON 导入(合并语义) |
| `LoadFrom` | `LoadFrom(r io.Reader) error` | 流式导入 |
| `Backup` | `Backup(path string) error` | 一致性快照备份 |
| `Vacuum` | `Vacuum() error` | 压缩数据库,回收磁盘空间 |
| `DBSize` | `DBSize() (int64, error)` | 当前 DB 键值总字节数 |
### 错误常量(sentinel error)
| 错误 | 含义 | 使用方式 |
|------|------|---------|
| `ErrKeyNotFound` | 键不存在 | `errors.Is(err, kvstore.ErrKeyNotFound)` |
| `ErrInvalidDBIndex` | Select 库编号越界 | 同上 |
| `ErrInvalidDumpData` | 导入数据非合法 JSON 数组 | 同上 |
| `ErrInvalidDumpDBIndex` | 导入数据中 db 越界 | 同上 |
| `ErrEmptyKey` | 导入数据中包含空 key | 同上 |
---
## 🗂️ 支持的功能与格式
| 类别 | 支持内容 |
|------|---------|
| 📊 数据类型 | `[]byte` 二进制 / `string` / 任意结构体(经 JSON) |
| 🗄️ 逻辑库 | 16 个(DB 0~15),`Select` 切换,数据完全隔离 |
| 🔁 持久化 | SQLite 单文件,WAL 模式,崩溃恢复 |
| ⚙️ 并发 | 多连接读写、事务、busy 等待(多进程) |
| 📦 序列化格式 | Dump JSON 数组:`[{"db":0,"key":"...","value":"base64"}]` |
| 🧵 存储引擎 | SQLite(modernc.org/sqlite v1.56+,纯 Go 无 CGO) |
---
## ⚙️ 配置选项
sqlkv 在打开数据库时自动应用合理的默认优化配置,无需额外设置即可获得良好性能:
| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `journal_mode` | `WAL` | 写前日志模式,读写互不阻塞 |
| `busy_timeout` | `5000ms` | 多进程/多连接写冲突时等待而非直接报错 |
| `synchronous` | `NORMAL` | WAL 官方推荐组合,大幅提升写吞吐(崩溃最多丢最近几笔,不会损坏库) |
| `cache_size` | `64MB` | SQLite 页缓存,减少高频读磁盘 I/O |
| `mmap_size` | `256MB` | 数据库文件内存映射,降低读系统调用 |
| `temp_store` | `MEMORY` | 排序等临时数据放内存 |
| `MaxOpenConns` | `5` | 最大打开连接数(读并行 + 写串行) |
| `MaxIdleConns` | `5` | 最大空闲连接数(复用,避免反复重建) |
| `ConnMaxIdleTime` | `5min` | 空闲连接超时回收,释放文件句柄(Windows 友好) |
> ⚠️ **关于 `synchronous=NORMAL`**:该设置牺牲"断电丢失最近几笔写入"换取显著写性能,但**绝不会损坏数据库**。若你的场景要求每笔写入必须可靠落盘,请在 `New` 的 DSN 中移除该 PRAGMA。
---
## 📁 项目结构
```
sqlkv/
├── go.mod # 模块定义(gitee.com/MM-Q/sqlkv)
├── go.sum # 依赖校验
├── LICENSE # MIT 许可证
├── sqlkv.go # 核心结构:New / Close / Select / 预编译 / 连接池配置
├── basic.go # 基础操作:Set / Get / Del / Keys / ForEach / 批量操作
├── admin.go # 管理操作:Flush / Backup / Vacuum / Dump / Load / DBSize
├── convenience.go # 便捷方法:SetString / GetString / SetJSON / GetJSON
├── sqlkv_test.go # 核心结构测试(New / Select / 并发 / 库隔离)
├── basic_test.go # 基础操作测试
├── admin_test.go # 管理操作测试
└── convenience_test.go # 便捷方法测试
```
---
## 🧪 测试说明
项目包含 **40+** 个测试用例,覆盖全部公开 API、边界条件与并发安全:
```bash
# 运行全部测试(含 -race 数据竞争检测,推荐)
go test -race -count=1 ./...
# 运行全部测试(详细输出)
go test -v ./...
# 静态检查
go vet ./...
golangci-lint run ./...
```
覆盖范围:基础读写、覆盖写、缺失键错误语义、`Set(nil)` 边界、库间数据隔离、并发读写(`-race`)、批量操作、JSON 序列化往返、导入格式校验(非法输入零写入)、备份恢复、Dump/Load 往返等。
---
## 🤝 贡献指南
欢迎贡献!请遵循以下流程:
1. **Fork** 本仓库并克隆到本地
2. 创建特性分支:`git checkout -b feature/your-feature`
3. 编写代码并**补充相应测试**(`*_test.go`)
4. 确保通过:`go vet ./... && go test -race ./...`
5. 提交并推送:`git push origin feature/your-feature`
6. 发起 **Pull Request**(请清晰描述改动内容与动机)
**开发约定**
- 保持零 CGO 与零额外依赖(仅标准库 + modernc.org/sqlite)
- 所有导出的函数/方法需添加中文函数级注释
- 新 API 必须配套测试用例
- 保持 Redis 风格 API 的一致性
---
## 📄 许可证
本项目基于 **MIT License** 开源,Copyright © 2026 M乔木。
你可以自由地使用、复制、修改、合并、发布、分发、再许可及销售本软件的副本,前提是保留原始版权声明。详见 [LICENSE](./LICENSE)。
---
## 📫 联系方式与相关链接
| 资源 | 链接 |
|------|------|
| 📦 项目仓库 | [https://gitee.com/MM-Q/sqlkv](https://gitee.com/MM-Q/sqlkv) |
| 🔗 Git 克隆 | `git clone https://gitee.com/MM-Q/sqlkv.git` |
| ⬇️ Go 安装 | `go get gitee.com/MM-Q/sqlkv` |
| 🧱 底层驱动 | [modernc.org/sqlite](https://gitlab.com/cznic/sqlite)(纯 Go SQLite 驱动) |
| 🗄️ 数据库 | [SQLite 官网](https://www.sqlite.org/) |
---
**如果这个项目对你有帮助,欢迎 ⭐ Star 支持!**
[仓库地址:https://gitee.com/MM-Q/sqlkv](https://gitee.com/MM-Q/sqlkv)