【Tauri2】035——sql和sqlx

[复制链接]
发表于 2025-9-19 09:47:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
前言

这篇就来看看插件sql
SQL | Tauri
https://tauri.app/plugin/sql/
正文

预备

添加依赖
  1. tauri-plugin-sql = {version = "2.2.0",features = ["sqlite"]}
复制代码
features可以是mysql、sqlite、postsql
进去features看看
  1. sqlite = [
  2.     "sqlx/sqlite",
  3.     "sqlx/runtime-tokio",
  4. ]
复制代码
可以发现本质利用的是sqlx
sqlx - Rust
https://docs.rs/sqlx/latest/sqlx/注册插件
  1.         .plugin(tauri_plugin_sql::Builder::default().build())
复制代码
并不像其他插件一样,有init方法,由于须要一些配置,比如毗连数据库。
配置

要想配置数据库,假如数据库内里有东西,比如表,须要用到如下函数add_migrations
  1.     pub fn add_migrations(mut self,
  2.                           db_url: &str,
  3.                           migrations: Vec<Migration>) -> Self
复制代码
须要传入db_url和migrations
比如db_url可以设置sqlite:start.db
migrations是个Vec,元素范例是Migration
Migration的界说如下
  1. #[derive(Debug)]
  2. pub struct Migration {
  3.     pub version: i64,
  4.     pub description: &'static str,
  5.     pub sql: &'static str,
  6.     pub kind: MigrationKind,
  7. }
复制代码
 MigrationKind是指定迁移的范例
  1. #[derive(Debug)]
  2. pub enum MigrationKind {
  3.     Up,
  4.     Down,
  5. }
复制代码
项目布局如下 

在migration.rs中
  1. use tauri_plugin_sql::{Migration,MigrationKind};
  2. pub fn get_migration()->Vec<Migration>{
  3.     vec![
  4.         // Define your migrations here
  5.         Migration {
  6.             version: 1,
  7.             description: "Create book table",
  8.             sql: r"
  9.                      CREATE TABLE book (
  10.                         id INTEGER PRIMARY KEY,
  11.                         author TEXT,
  12.                         title TEXT,
  13.                         published_date date
  14.                             );
  15.                 ",
  16.             kind: MigrationKind::Up,
  17.         }
  18.     ]
  19. }
复制代码
 创建了一张表
注册
  1.        .plugin(tauri_plugin_sql::Builder::default()
  2.             .add_migrations("sqlite:start.db",get_migration())
  3.             .build())
复制代码
 想要在后端利用

怎么在后端利用,这确实是个问题,笔者发现似乎没有在后端利用的东西,全都是前端调用
比如说
  1.     pub(crate) async fn connect<R: Runtime>(
  2.         conn_url: &str,
  3.         _app: &AppHandle<R>,
  4.     ) -> Result<Self, crate::Error>
复制代码
按原理来说,connect应该可以利用,但是这是私有的,只在crate内部公开,
笔者也没找到怎么利用,
看看内部的通讯函数
  1. #[command]
  2. pub(crate) async fn load<R: Runtime>(
  3.     app: AppHandle<R>,
  4.     db_instances: State<'_, DbInstances>,
  5.     migrations: State<'_, Migrations>,
  6.     db: String,
  7. ) -> Result<String, crate::Error> {
  8.     let pool = DbPool::connect(&db, &app).await?;
  9.     if let Some(migrations) = migrations.0.lock().await.remove(&db) {
  10.         let migrator = Migrator::new(migrations).await?;
  11.         pool.migrate(&migrator).await?;
  12.     }
  13.     db_instances.0.write().await.insert(db.clone(), pool);
  14.     Ok(db)
  15. }
复制代码
  1. impl DbPool {
  2.     pub(crate) async fn connect
  3.     pub(crate) async fn migrate
  4.     pub(crate) async fn close(&self)
  5.     pub(crate) async fn execute
  6.     }
复制代码
可以看出利用了DbInstances和Migrations,两个State
要先毗连 DbPool::connect,但是这个connect没公开,其他方法也没有公开
看来这个插件就是写在前端的。后端无法利用。
要么利用sqlx,要么修改源码。额,都很贫苦。
笔者不在后端利用这个插件。直接利用sqlx
sqlx

临时丢掉插件,简单利用一下这个crate
创建一个数据库和book表

添加依赖
  1. sqlx = { version = "0.8.5", features = ["sqlite", "runtime-tokio"] }
复制代码
 

在connect.rs中,界说DbInstances ,然后将其注册成State
  1. use sqlx::sqlite::SqlitePoolOptions;
  2. use sqlx::Sqlite;
  3. use sqlx::Pool;
  4. use tauri::{command, AppHandle, State};
  5. async fn connect()-> Pool<Sqlite> {
  6.     SqlitePoolOptions::new()
  7.         .connect("sqlite:start.db").await.unwrap()
  8. }
  9. pub struct DbInstances {
  10.     pub db: Pool<Sqlite>
  11. }
  12. impl DbInstances {
  13.     pub async fn new() -> Self {
  14.         Self {
  15.             db: connect().await
  16.         }
  17.     }
  18. }
复制代码
通讯函数 
  1. use sqlx::Executor;
  2. use crate::sql::connect::DbInstances;
  3. use tauri::{command, AppHandle, State};
  4. use tauri::Result;
  5. #[command]
  6. pub async fn insert_one(state: State<'_, DbInstances>)->Result<()> {
  7.     let db=state.db.clone();
  8.     db.execute(r"
  9.         INSERT INTO book (id, author, title, published_date) VALUES (2, 'gg', 'good', '2024-04-20');
  10.     "
  11.     ).await.unwrap();
  12.     Ok(())
  13. }
复制代码
注册State和通讯函数之后。
实行后

乐成。简单地利用了一下sqlx
前端利用插件sql

既然这个插件是为前端服务的,就在前端简单利用一下。
添加依赖
  1. pnpm add @tauri-apps/plugin-sql
复制代码
后端注册完成后,简单的代码如下 
  1. import Database,{QueryResult}  from '@tauri-apps/plugin-sql';
  2. export async function useSql(){
  3.     const db = await Database.load('sqlite:start.db');
  4.     let a=await db.execute("INSERT INTO book (id, author, title, published_date) VALUES (22, 'gg', 'good', '2024-04-20');");
  5.     console.log(a)
  6.     let b=await db.select("select * from book")
  7.     console.log(b)
  8.     db.close()
  9. }
复制代码
全部的通讯函数都在这里。 
利用load方法和execuct方法,须要配置权限
  1.     "sql:default",
  2.     "sql:allow-execute"
复制代码
 通讯函数load

  1. #[command]
  2. pub(crate) async fn load<R: Runtime>(
  3.     app: AppHandle<R>,
  4.     db_instances: State<'_, DbInstances>,
  5.     migrations: State<'_, Migrations>,
  6.     db: String,
  7. ) -> Result<String, crate::Error> {
  8.     let pool = DbPool::connect(&db, &app).await?;
  9.     if let Some(migrations) = migrations.0.lock().await.remove(&db) {
  10.         let migrator = Migrator::new(migrations).await?;
  11.         pool.migrate(&migrator).await?;
  12.     }
  13.     db_instances.0.write().await.insert(db.clone(), pool);
  14.     Ok(db)
  15. }
复制代码
先毗连,看看DbPool::connect方法
  1. match conn_url
  2.             .split_once(':')
  3.             .ok_or_else(|| crate::Error::InvalidDbUrl(conn_url.to_string()))?
  4.             .0
  5.         {
  6.             #[cfg(feature = "sqlite")]
  7.             "sqlite" => {
  8.                 let app_path = _app
  9.                     .path()
  10.                     .app_config_dir()
  11.                     .expect("No App config path was found!");
  12.                 create_dir_all(&app_path).expect("Couldn't create app config dir");
  13.                 let conn_url = &path_mapper(app_path, conn_url);
  14.                 if !Sqlite::database_exists(conn_url).await.unwrap_or(false) {
  15.                     Sqlite::create_database(conn_url).await?;
  16.                 }
  17.                 Ok(Self::Sqlite(Pool::connect(conn_url).await?))
  18.             }
复制代码
  1. fn path_mapper(mut app_path: std::path::PathBuf, connection_string: &str) -> String {
  2.     app_path.push(
  3.         connection_string
  4.             .split_once(':')
  5.             .expect("Couldn't parse the connection string for DB!")
  6.             .1,
  7.     );
复制代码
对于sqlite:start.db可以发现位置实在是在app_config_dir+start.db
笔者是Window体系,位置如下


写相当路径会相对 app_config_dir。
可以写绝对路径,比如
  1. const db = await Database.load('sqlite:D:/start/start.db');
复制代码
固然,须要有表,结果如下

从官网的案例中可以发现
  1. const result = await db.execute(
  2. "UPDATE todos SET title = $1, status = $2 WHERE id = $3",
  3. [todos.title, todos.status, todos.id],
  4. );
复制代码
 可以在sql语句中利用占位符。根本操纵。
预加载

可以在配置文件中提前配置。不告急
  1.   "plugins": {
  2.     "sql": {
  3.       "preload": ["sqlite:start.db"]
  4.     }
  5.   },
复制代码
总结

这个插件实际上感觉就是对sqlx的封装。也不是很完全的封装,也没有对sql语句的封装。
等用于为前端提供了数据库毗连和实行的接口。



回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表