在开发 Flutter 应用时,本地存储往往是让人最头疼的一环。简单存个配置用 SharedPreferences 勉强够用;但只要上了数据量,无论是使用 SQLite 还是 Isar,接踵而来的就是 FFI 底层报错、繁琐的建表语句、以及让人心智负担极重的版本迁移脚本。
如果你也厌倦了为了存点本地数据而折腾一堆额外的配置和状态更新代码,那么今天,我将带你快速上手一款真正“开箱即用”的新一代纯 Dart 数据库 —— Tostore。
这是一款专为 Dart 和 Flutter 开发者量身定做的分布式引擎,但对我们前端开发者来说,它最吸引人的不是那些高大上的底层概念,而是它极其简单的上手体验、不需要写 SQL 语句、以及能自动刷新 UI 的魔法能力。
接下来,我们将从零开始,用最接地气的方式,带你把 Tostore 集成到你的应用中。
准备工作:引入 Tostore
在开始写代码之前,我们需要先把 Tostore 请进你的项目。打开项目根目录下的 pubspec.yaml 文件,在 dependencies 节点下添加:
dependencies:
flutter:
sdk: flutter
tostore: any # 建议去 pub.dev 看下最新版本号替换 any
然后在终端运行 flutter pub get,准备工作就完成了。就是这么简单,不需要配置复杂的 C++ 环境,因为它是纯 Dart 写的。
场景一:极简键值存储 (KV),完全不需要建表
很多时候,我们其实并不需要建很复杂的表,只是想存个“用户是否登录了”、“夜间模式开关”这种简单的配置。这就是常说的“键值对(Key-Value)”。
Tostore 内置了极其顺滑的 KV 功能。如果你只是想存这类简单数据,那你根本不需要定义什么表结构,拿来即用:
import 'package:tostore/tostore.dart';
// 先打开数据库,这是后续一切操作的起点
final db = await ToStore.open();
// 存入一条数据,比如主题设置
await db.setValue('theme', 'dark');
// 哪怕存个数字也没问题
await db.setValue('login_attempts', 3);
// 读取刚才存入的数据
final theme = await db.getValue('theme');
print('当前主题:$theme'); // 输出: 当前主题:dark
// 如果不用了,删掉即可
await db.removeValue('theme');
简单吧?不需要定义表结构,比 SharedPreferences 更可靠。最重要的是,不管你存多少键值数据,实测普通手机10亿条数据,它的查询速度都不会受到数据规模的影响。
场景二:正式建表存数据(再也不用写头秃的 SQL 脚本)
当我们要存诸如“用户列表”、“日记信息”、“商品清单”这种有结构的数据时,就需要“建表”了。
用老一代数据库,你可能要手写一长串 CREATE TABLE IF NOT EXISTS... 的语句。但在 Tostore 里,一切都是清爽的 Dart 代码对象配置,也就是 Schema(结构)。
你可以把这当做是告诉数据库:“嘿,我需要一个装用户的收纳盒,里面有名字和年龄这两个隔间”。
// 在打开数据库时,一起把咱们需要的“表结构”传进去
final db = await ToStore.open(
schemas: [
// 定义一张名叫 'users' 的表
const TableSchema(
name: 'users',
// 定义表的字段
fields: [
FieldSchema(
name: 'username',
type: DataType.text, // 这是一个文本类型的字段
unique: true, // 加上这个,名字就不会重复存入
nullable: false, // 开启约束:这个字段必定要有值,不能是空的
minLength: 2, // 开启约束:名字长度不能少于 2 个字符
),
FieldSchema(
name: 'age',
type: DataType.integer, // 这是一个整数类型的字段
createIndex: true, // 创建索引,以后按“年龄”查询或排序时速度会快到起飞!
),
]
),
]
);
最牛逼的一个点来了: 以后如果业务变了,你的老用户升级了新版本,你需要给表里加个“邮箱”字段。你什么版本迁移脚本(Migration)都不用写!直接在上面的数组里加上这一行就行了: FieldSchema(name: 'email', type: DataType.text)。 Tostore 启动时只要用眼一扫,它底层会自动把旧数据全部迁移好,绝对不会报错导致白屏,堪称新手的福星!
场景三:极其优雅的数据“增删改查”操作
有了刚才建好的表,我们就可以开始真正的业务逻辑了。Tostore 的方法非常语义化,你甚至不需要看文档,只看方法名就能知道它在干什么。
1. 插入数据 (Insert)
要把数据存进数据库,只需丢一个 Map(字典)给它就行:
await db.insert('users', {
'username': '老王',
'age': 35,
});
await db.insert('users', {
'username': '小李',
'age': 20,
});
2. 查询数据 (Query)
查询数据极其连贯,感觉就像在写英语短句一样自然:
// 查出全表的数据
final allUsers = await db.query('users');
print('所有人:$allUsers');
// 条件过滤:我想找年龄大于 18 岁的人
final adults = await db.query('users')
.whereGreaterThan('age', 18) // 连贯的链式调用,极其优雅
.limit(20);
// 模式匹配:找名字里带有“王”字的人
final wangs = await db.query('users')
.whereLike('username', '%王%')
.limit(20);
提示:查询时最好带上 .limit() 限制返回条数,这是一个好习惯,可以避免一次提取太多数据撑爆手机内存。
3. 更新与删除 (Update & Delete)
找到了目标人选,我们就能进行修改或开除了:
// 小李过生日了,年龄更新成 21 岁
await db.update('users', {
'age': 21
}).whereEqual('username', '小李');
// 老王离职了,直接删掉他的记录
await db.delete('users').whereEqual('username', '老王');
场景四:终极魔法 —— 让 UI 自动响应数据变化
在 Flutter 开发里,状态同步是最让人头疼的。你在详情页修改了用户的年龄,怎么让外部列表页的数字也能瞬间变过来?以前我们需要用各种通知工具(比如 Provider/GetX 等)折腾半天。
而这也是 Tostore 为大家“省事”的精髓所在:自带推送机制。
你只需要把刚才的“查询”动作结尾,从获取静态结果,变成 .watch().listen(),数据库只要发生了变化(不管是插入还是更新),它都会自己把最新结果发给你,你的界面只需要跟着重绘就行:
// 这里的 watch() 就是见证奇迹的时刻
db.query('users')
.whereGreaterThan('age', 18)
.watch()
.listen((users) {
// 这里的 print 如果换成 setState()
// 一旦有超过 18 岁的新人加入表里,或者有人刚满 18 岁,这里就会自动收到包含他名字的最新列表!
print('成年人列表发生变动啦,最新名单看这里: $users');
});
这个操作可以说是把 Flutter 开发者最厌烦的状态管理胶水代码全给扔进了历史的垃圾堆。
附加题:多用户系统?一行代码搞定数据切分
如果你要开发一个支持多个账号登录的 App(比如切换账号)。以前为了防止 A 用户看到 B 用户的聊天记录,你得在每条查询语句里拼命加上 WHERE userId = xxx,一旦漏写一句就会“串号”酿成事故。
Tostore 引入了极其先进的“多空间(Space)隔离”架构。不同空间的数据在物理文件上是彻底隔离的:
// 当小李登录成功后,直接让引擎切换到小李的空间
// 这里的 keepActive=true 表示切换后保持登录活跃状态,直到你主动关闭退出
await db.switchSpace(spaceName: 'user_xiaoli', keepActive: true);
// 此时,你所有的增删改查,都自动限定在小李的盒子里!
await db.setValue('theme', 'dark'); // 这是小李的主题色
await db.insert('users', {...}); // 这是小李的好友列表
// 当小李退出登录时退出并清除活跃状态,就这么简单!
await db.close(keepActiveSpace: false);
再也不用害怕忘记写条件导致数据串号了,这就是底层物理隔离带给开发者的安全感。
总结
到目前为止,我们仅仅用了几十段非常直观、简单的代码,就走完了很多传统数据库需要好几天才能趟平的坑。
Tostore 简单易用,让你把精力全用在写业务上,它同时还拥有强大的纠错恢复机制、甚至还支持内置高维向量做端侧 AI…… 但作为入门这并不是本篇的重点。
- Pub 主页: pub.dev/packages/to…
- GitHub 源码: github.com/tocreator/t…