首页 / Tauri 2 入门教程 / 本地存储与数据库

Tauri 2 入门教程

本地存储与数据库

本教程共 48 篇 · 第 38 篇 · 更新于 2026-08-09 · 约 9 分钟阅读

TauriTauri 2 入门教程plugin-storeplugin-sqlSQLite键值存储数据库迁移本地存储

本节目标:读完你能用 @tauri-apps/plugin-store 存取键值对,用 @tauri-apps/plugin-sql 连接 SQLite 数据库并执行 SQL,还能根据场景选对存储方案。

桌面应用经常需要在本地存东西:用户的主题偏好、待办列表、缓存数据。Tauri 2 提供了两个官方插件来搞定这件事——plugin-store 适合轻量的键值存储,plugin-sql 适合需要复杂查询的关系型数据库。一个像便利贴,一个像档案柜,各有各的用武之地。

plugin-store:键值存储

plugin-store 的思路很简单:把数据以 JSON 格式存到文件里,前端用 set / get 读写,像用 localStorage 一样简单。但它比 localStorage 强在——数据持久化到磁盘,应用重启后还在。

安装与注册

两端都要装:

cd src-tauri
cargo add tauri-plugin-store
// src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_store::Builder::new().build())
        .run(tauri::generate_context!())
        .expect("运行 Tauri 应用时出错");
}
npm install @tauri-apps/plugin-store

读写键值对

前端的用法非常直白:

import { load } from "@tauri-apps/plugin-store";

// 加载(或创建)一个 store 文件
const store = await load("settings.json", { autoSave: false });

// 写入一个键值对
await store.set("theme", "dark");
await store.set("volume", 80);
await store.set("user", { name: "小明", age: 20 });

// 读取
const theme = await store.get("theme");
console.log(theme); // "dark"

const user = await store.get("user");
console.log(user); // { name: "小明", age: 20 }

// 手动保存到磁盘
await store.save();

load("settings.json") 会创建或读取一个名为 settings.json 的文件,位置在应用的数据目录下。set 只是改了内存里的值,要真正写入磁盘需要调 save()

Tip

autoSave 不设 false 时,默认行为是防抖保存——改完数据后等 100ms 没有新改动就自动写盘。如果你频繁修改数据又不想手动调 save(),直接用默认的 autoSave 就行:const store = await load("settings.json")

LazyStore:懒加载

如果你不想在应用启动时就加载 store 文件,可以用 LazyStore——它只在第一次访问时才真正加载:

import { LazyStore } from "@tauri-apps/plugin-store";

const store = new LazyStore("settings.json");

// 第一次调用 get/set 时才真正读取文件
await store.set("theme", "light");
const theme = await store.get("theme");

LazyStoreload() 返回的 Store 接口一样,区别只是加载时机。对于大文件或不一定用到的 store,用 LazyStore 能省启动时间。

Rust 端操作 store

store 也能在 Rust 端直接读写。用 app.store() 拿到同一个 store 实例(和前端共享):

use tauri_plugin_store::StoreExt;
use serde_json::json;

// 在 setup 或命令里
let store = app.store("settings.json")?;

store.set("theme", json!("dark"));
store.set("user", json!({ "name": "小明", "age": 20 }));

let value = store.get("theme").expect("没取到");
println!("{}", value); // "dark"
Note

Rust 端存入的值必须是 serde_json::Value 类型,这样才能和前端 JS 兼容。用 json! 宏可以方便地构造 JSON 值。

store 的权限

和所有插件一样,store 默认是锁住的。在 capabilities/default.json 中加 store:default

{
  "permissions": [
    "core:default",
    "store:default"
  ]
}

plugin-sql:关系型数据库

当数据量大了、需要复杂查询时,键值存储就不够用了。plugin-sql 让前端直接连 SQLite、MySQL 或 PostgreSQL,底层用的是 Rust 的 sqlx 库。

安装与选择数据库引擎

先装插件,再选一个数据库引擎:

cd src-tauri
cargo add tauri-plugin-sql
cargo add tauri-plugin-sql --features sqlite

--features 决定启用哪个驱动。SQLite 最常用(本地应用首选),MySQL 和 PostgreSQL 适合需要连远程数据库的场景。三个可以同时启用。

// src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_sql::Builder::default().build())
        .run(tauri::generate_context!())
        .expect("运行 Tauri 应用时出错");
}
npm install @tauri-apps/plugin-sql

连接数据库并执行 SQL

前端连接 SQLite 非常简单:

import Database from "@tauri-apps/plugin-sql";

// 连接(不存在则创建)一个 SQLite 数据库文件
const db = await Database.load("sqlite:test.db");

// 建表
await db.execute(`
  CREATE TABLE IF NOT EXISTS todos (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,
    status TEXT DEFAULT 'pending'
  )
`);

// 插入数据(用 $1, $2 占位)
await db.execute(
  "INSERT INTO todos (title, status) VALUES ($1, $2)",
  ["学 Tauri", "done"]
);

// 查询
const rows = await db.select("SELECT * FROM todos");
console.log(rows);
// [{ id: 1, title: "学 Tauri", status: "done" }]

Database.load("sqlite:test.db") 中的 sqlite: 前缀表示用 SQLite 引擎,test.db 是文件名,路径相对于应用配置目录(BaseDirectory::AppConfig)。MySQL 和 PostgreSQL 则传完整的连接字符串:

// MySQL
const db = await Database.load("mysql://user:password@host/test");

// PostgreSQL
const db = await Database.load("postgres://user:password@host/test");
Tip

不同数据库的占位符语法不同:SQLite 和 PostgreSQL 使用 $1, $2, $3(编号式),MySQL 使用 ?, ?, ?(问号式)。参数以数组传入,按顺序对应。

查询与参数绑定

execute 用于写操作(INSERT / UPDATE / DELETE),返回受影响的行数。select 用于读操作(SELECT),返回对象数组:

// 更新
const result = await db.execute(
  "UPDATE todos SET status = $1 WHERE id = $2",
  ["done", 1]
);
console.log(result.rowsAffected); // 1

// 查询
const rows = await db.select(
  "SELECT * FROM todos WHERE status = $1",
  ["done"]
);
console.log(rows);
// [{ id: 1, title: "学 Tauri", status: "done" }]

数据库迁移(Migrations)

实际应用中,数据库表结构会随版本迭代而变化。plugin-sql 内置了迁移(migration)机制,让你用版本号管理表结构变更:

use tauri_plugin_sql::{Builder, Migration, MigrationKind};

let migrations = vec![
    Migration {
        version: 1,
        description: "create_initial_tables",
        sql: "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);",
        kind: MigrationKind::Up,
    },
    Migration {
        version: 2,
        description: "add_email_column",
        sql: "ALTER TABLE users ADD COLUMN email TEXT;",
        kind: MigrationKind::Up,
    },
];

tauri::Builder::default()
    .plugin(
        Builder::default()
            .add_migrations("sqlite:mydatabase.db", migrations)
            .build(),
    )
    .run(tauri::generate_context!())
    .expect("运行 Tauri 应用时出错");

每个 Migration 有四个字段:版本号、描述、SQL 语句、迁移方向(Up 表示正向执行,Down 表示回滚)。插件会自动记录已执行的迁移版本,下次启动时只跑还没执行过的。

Note

所有迁移都在事务中执行,保证原子性。如果某条迁移失败了,整个事务会回滚,数据库保持一致状态——不会出现「跑到一半表建了一半」的尴尬。

你也可以让迁移在前端 load() 时自动触发:

const db = await Database.load("sqlite:mydatabase.db");
// load 时会检查并执行未完成的迁移

如果需要在应用启动时就准备好数据库,可以在 Rust 端通过 .plugin(tauri_plugin_sql::Builder::default().add_migrations(...).build()) 注册迁移,插件会在启动时自动执行;也可以直接在前端首次调用 Database.load() 时加载。

sql 的权限

plugin-sql 默认也是锁住的。前端要用,得在 capabilities/default.json 里授权:

{
  "permissions": [
    "core:default",
    "sql:default",
    "sql:allow-execute"
  ]
}

sql:default 开放基础能力,sql:allow-execute 允许执行 SQL 语句。如果你只想让前端查询不允许修改,可以只开 sql:allow-select 而不给 sql:allow-execute,实现读写分离控制。

两种方案怎么选

维度plugin-storeplugin-sql
数据模型键值对(JSON)关系型(表、行、列)
查询能力只能按 key 取支持 SQL 全套查询
适合场景配置、偏好、小量缓存待办、笔记、业务数据
复杂度极低,开箱即用需要 SQL 基础
数据量几百到几千个 key可处理百万级行

一句话总结:数据简单、不需要查询,用 store;数据有结构、需要筛选和关联,用 sql。两者并不互斥,同一个应用里可以同时用——配置存 store,业务数据存 SQLite。

小结

Tauri 2 提供两个本地存储插件:plugin-store 是轻量 KV 存储,用 load() 打开、set() / get() 读写、save() 持久化,适合存配置和偏好;plugin-sql 是关系型数据库接口,支持 SQLite / MySQL / PostgreSQL,用 Database.load() 连接、execute() 执行写操作、select() 执行查询,内置版本化迁移机制。两个插件都遵循 Tauri 2 的权限模型——默认全锁,需要在 capabilities 里显式授权。选择方案时看数据模型:简单键值用 store,有结构有关系就用 sql。