Tauri 开发实践 — Tauri 集成本地数据库

简介: 本文介绍了在 Tauri 框架中集成本地数据库的几种方案,包括直接绑定 SQLite、使用第三方数据库库和使用 tauri-plugin-sql-api 插件。最终选择了 tauri-plugin-sql-api,因为它集成简单、支持多种数据库类型,并且与 Tauri 框架深度整合,提升了开发效率和安全性。文章详细介绍了如何安装和使用该插件,以及如何编写核心代码实现数据库操作。

本文首发微信公众号:前端徐徐。

前言

Tauri 是一个构建跨平台桌面应用程序的框架,利用 Web 技术构建前端,并使用 Rust 构建后端。它以其小巧的体积和高性能受到开发者的欢迎。在开发过程中,我们常常需要数据本地持久化, 所以会需要与本地数据库进行交互 。

方案比较

在 Tauri 中集成本地数据库有多种方案,常见的包括:

  1. SQLite 通过直接绑定
  2. 使用第三方数据库库
  3. Tauri 插件:tauri-plugin-sql-api

1. SQLite 通过直接绑定

优点:

  • 直接控制:可以完全掌控数据库的操作和配置。
  • 轻量级:SQLite 非常适合桌面应用,文件存储简单。

缺点:

  • 复杂性:需要手动处理所有数据库连接、查询和事务。
  • 安全性:需要自行管理数据库文件的访问权限。

2. 使用第三方数据库库

优点:

  • 功能丰富:第三方库通常提供丰富的功能和更好的文档支持。
  • 社区支持:很多库有活跃的社区,能够快速获取帮助。

缺点:

  • 依赖管理:需要处理额外的依赖管理和库更新。
  • 体积增加:引入额外的库可能会增加应用的体积。

3. Tauri 插件:tauri-plugin-sql-api

优点:

  • 集成方便:专为 Tauri 设计的插件,易于集成。
  • 多数据库支持:支持 SQLite、MySQL 和 PostgreSQL。
  • 安全性:通过 Tauri 的安全模型,确保数据库操作的安全性。

缺点:

  • 功能限制:相比直接使用数据库库,插件可能有一些功能限制。

综合考虑,我们选择 tauri-plugin-sql-api 作为集成本地数据库的方案。它的集成简单、支持多种数据库类型,并且与 Tauri 框架深度整合,能够有效地提升开发效率和安全性。  

使用 tauri-plugin-sql-api 集成本地数据库  

此插件要求 Rust 版本至少为 1.65。

我们推荐以下三种通用的安装方法:

  1. 使用 crates.io 和 npm(最简单,但需要信任我们的发布流程是否正常)
  2. 从 GitHub 上直接拉取源代码,使用 git 标签/修订哈希(最安全)
  3. 在你的 Tauri 项目中使用 git 子模块安装这个仓库,然后使用文件协议来引入源代码(最安全,但使用起来不方便)

安装核心插件

在你的 Cargo.toml 文件中添加以下内容:

src-tauri/Cargo.toml

toml
复制代码
[dependencies.tauri-plugin-sql]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v1"
features = ["sqlite"] # 或者 "postgres", 或 "mysql"

安装 JavaScript 依赖

你可以使用你喜欢的 JavaScript 包管理器来安装:

注意:由于大多数 JavaScript 包管理器无法从 git 单仓库安装包,我们提供了每个插件的只读镜像。这使得安装选项 2 更加方便使用。

pnpm add https://github.com/tauri-apps/tauri-plugin-sql#v1
# 或
npm add https://github.com/tauri-apps/tauri-plugin-sql#v1
# 或
yarn add https://github.com/tauri-apps/tauri-plugin-sql#v1

编写核心代码

DatabaseService

构建db核心类,初始化DB,这里只是做的key-value的表

import Database from "tauri-plugin-sql-api";
import {ENV_MODE} from "@/utils/const"
class DatabaseService {
  private db!: Database;
  private dbReady: Promise<void>;
  constructor() {
    this.dbReady = this.initDatabase();
  }
  private async initDatabase() {
    try {
      this.db = await Database.load(ENV_MODE !== 'development' ? "sqlite:xtools.db" : "sqlite:xtools_test.db");
      await this.db.execute(`
        CREATE TABLE IF NOT EXISTS key_value (
          key TEXT PRIMARY KEY,
          value TEXT
        )
      `);
    } catch (error) {
      console.error("Error initializing database:", error);
      throw error; 
    }
  }
  public async getDbInstance(): Promise<Database> {
    await this.dbReady;
    return this.db;
  }
}
export default new DatabaseService();

KeyValueStore

keyValue的增删改查,方便外部使用

import DatabaseService from './dbService';
class KeyValueStore {
  private dbPromise = DatabaseService.getDbInstance();
  
  public async set(key: string, value: string): Promise<void> {
    const db = await this.dbPromise;
    try {
      await db.execute('REPLACE INTO key_value (key, value) VALUES (?, ?)', [key, value]);
    } catch (error) {
      console.error(`Error setting value for key "${key}":`, error);
      throw error; 
    }
  }
  public async get(key: string): Promise<string | null> {
    const db = await this.dbPromise;
    try {
      const result = await db.select<{ value: string }[]>('SELECT value FROM key_value WHERE key = ?', [key]);
      return result.length > 0 ? result[0].value : null;
    } catch (error) {
      console.error(`Error getting value for key "${key}":`, error);
      throw error;
    }
  }
  public async delete(key: string): Promise<void> {
    const db = await this.dbPromise;
    try {
      await db.execute('DELETE FROM key_value WHERE key = ?', [key]);
    } catch (error) {
      console.error(`Error deleting key "${key}":`, error);
      throw error;
    }
  }
  public async getAll(): Promise<{ key: string; value: string }[]> {
    const db = await this.dbPromise;
    try {
      const result = await db.select<{ key: string; value: string }[]>('SELECT key, value FROM key_value');
      return result;
    } catch (error) {
      console.error("Error getting all key-value pairs:", error);
      throw error;
    }
  }
}
export default KeyValueStore;

外部使用

这里判断了一下环境,如何是TAURI环境我们就用本地数据库,否则就用localStorage,兼容浏览器环境。

import { KeyValueStore } from '@/db';
import {IS_TAURI} from '@/utils/const'
export const getStore = async (key:string) => {
    if (IS_TAURI) {
        const store = new KeyValueStore();
        const val =   await store.get(key);
        return val
    } else {
        return localStorage.getItem(key)
    }
}
export const setStore = async (key:string,value:string) => {
    if (IS_TAURI) {
        const store = new KeyValueStore();
        await store.set(key,value);
    } else {
        localStorage.setItem(key,value)
    }
}

总结

通过以上步骤,我们在 Tauri 应用中成功集成了 tauri-plugin-sql-api 插件,实现了与本地 SQLite 数据库的交互。tauri-plugin-sql-api 插件不仅支持 SQLite,还支持其他类型的数据库,如 MySQL 和 PostgreSQL,开发者可以根据需求进行选择。通过 Tauri 的这种插件化设计,使得开发者能够轻松地将强大的 Rust 后端功能集成到现代前端框架中,从而构建高性能的跨平台桌面应用程序。

源码

https://github.com/Xutaotaotao/XTools/tree/feature-tauri-v1/src/db

相关文章
|
1天前
|
资源调度 前端开发 JavaScript
前端研发链路之脚手架
本文首发于微信公众号“前端徐徐”。文章介绍了前端开发中脚手架工具的重要性及其工作原理。脚手架工具能够大幅提升开发效率,确保代码质量和项目一致性。文章详细探讨了脚手架的历史、工作原理、常见工具及其优势与潜在问题,并展望了其未来发展方向,帮助开发者更好地理解和应用脚手架工具。
14 4
前端研发链路之脚手架
|
1天前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
10 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
1天前
|
资源调度 JavaScript 前端开发
如何实现一个类似 vite 的脚手架并发布 npm
本文介绍了如何实现一个类似 Vite 的脚手架工具。通过详细解析和实践,文章分享了从零开始构建脚手架的过程,包括技术选型、开发步骤及发布 NPM 包的完整流程。最终目标是让用户能够通过 `yarn create electron-prokit myapp` 快速搭建 Electron 项目。项目源码可在 GitHub 上获取。
12 5
|
1天前
|
自然语言处理 JavaScript 前端开发
Tauri 开发实践 — Tauri 主题&多语言设置开发
本文首发于微信公众号「前端徐徐」,介绍了在 Tauri 应用中实现窗口主题设置与多语言支持的方法。主题设置包括静态和动态两种方式,前者在应用初始化时设定,后者允许运行时更改。文章详细描述了通过 tauri-plugin-theme 插件实现动态主题变更的过程,并提供了代码示例。对于多语言支持,文章介绍了使用 i18next 进行多语言文件初始化及切换的方法。最后,提供了完整的源码链接,帮助读者更好地理解和实践。
14 4
|
3天前
|
运维 监控 安全
高效运维管理:从混沌到有序的艺术
【10月更文挑战第4天】 在当今数字化时代,运维管理成为企业IT部门的重中之重。本文将探讨如何通过系统化的策略和工具,将看似杂乱无章的运维工作变得井井有条。我们将从基础架构监控、自动化工具的应用、到团队协作流程的优化等方面,逐步揭示实现高效运维管理的秘诀,并通过一些实际案例展示这些策略和方法的实际应用效果。希望本文能够为企业运维团队提供有价值的参考,帮助大家在纷繁复杂的工作中找到秩序与效率。
|
1月前
|
存储
CCF推荐A类会议和期刊总结:计算机体系结构/并行与分布计算/存储系统领域
中国计算机学会(CCF)2022年版推荐目录涵盖了计算机体系结构、并行与分布计算、存储系统领域的多个A类会议和期刊。本文汇总了这些顶级资源的全称、出版社、dblp网址及领域。包括《ACM计算机系统汇刊》、《ACM存储汇刊》等期刊,以及ACM PPoPP、USENIX FAST等会议,为研究人员提供了重要学术参考。
CCF推荐A类会议和期刊总结:计算机体系结构/并行与分布计算/存储系统领域
|
21天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
3天前
|
PHP 开发者
深入理解PHP中的面向对象编程
【10月更文挑战第4天】 在这篇文章中,我们将探讨PHP中的面向对象编程(OOP)的核心概念和实践。从类与对象的创建、继承、多态性到接口的应用,我们将一步步解析这些关键要素如何在PHP中得以实现和应用。通过具体的代码示例和场景分析,帮助读者更好地理解和掌握PHP的OOP技能,提升开发效率和代码质量。
|
3天前
|
安全 算法 网络安全
网络安全与信息安全:守护数字世界的坚盾在这个高度数字化的时代,网络安全和信息安全已成为全球关注的焦点。无论是个人隐私还是企业数据,都面临着前所未有的风险和挑战。本文将深入探讨网络安全漏洞、加密技术以及安全意识的重要性,旨在为读者提供实用的知识,帮助构建更加安全的网络环境。
【10月更文挑战第4天】 在数字化浪潮中,网络安全与信息安全成为不可忽视的议题。本文通过分析网络安全漏洞的类型与成因,探讨加密技术的原理与应用,并强调提升安全意识的必要性,为读者提供一套全面的网络安全知识框架。旨在帮助个人和企业更好地应对网络威胁,保护数字资产安全。
|
11天前
|
缓存 Python
Python编程中的装饰器深度探索
本文深入探讨了Python中装饰器的高级用法,从基本定义到实际应用,展示了如何利用装饰器提升代码的灵活性和可维护性。通过具体示例,解析了装饰器在函数增强、日志记录、权限验证等方面的应用,旨在帮助读者彻底理解和掌握这一强大的编程工具。