在 Rust 中使用 SQLX 集成 SQLite 數據庫

SQLite 是一個 c 語言庫,它實現了一個小型、快速、自包含、高可靠性、全功能的 SQL 數據庫引擎,與 Rust 的安全性和性能非常匹配。

sqlx crate 是一個很棒的工具,可以提供到各種數據庫 (包括 SQLite) 的異步連接。sqlx 的美妙之處在於它可以在編譯時檢查 SQL 查詢語句以及它與 Rust 異步特性的兼容。

在這篇文章中,我們將探索如何使用 sqlx 將 Rust 與 SQLite 無縫集成;我們還將探索 Rust 中異步編程的複雜性,確保你在將來的項目中能夠很好地處理數據庫操作。在文章的最後,你將擁有一個使用 Rust 創建和操作數據庫的工作示例,同時包含異步編程。

使用如下命令創建一個 Rust 新項目:

cargo new rust-sqlx-sqlite

在 Cargo.toml 文件中,加入以下依賴項:

[dependencies]
sqlx ={ version = "0.7.3"features = ["runtime-async-std-native-tls""sqlite"]}
async-std ={ version = "1.6"features = ["attributes"]}
futures = "0.3.18"

第一步,導入必要的 crate 和模塊

首先導入必要的 crate 和模塊,如數據庫操作的 sqlx 和處理操作結果的 std::result::Result。

use std::result::Result;
use sqlx::{sqlite::SqliteQueryResult, Sqlite, SqlitePool, migrate::MigrateDatabase};

第二步,創建數據庫 Schema

定義 create_schema 異步函數,用於在 SQLite 數據庫中創建一個新的 schema。它以數據庫 URL 作爲輸入,並嘗試使用 SqlitePool::connect 連接到數據庫。在建立連接之後,執行 SQL 命令以啓用外鍵並創建兩個表:settings 和 project,其中 project 具有對 settings 的外鍵引用。代碼如下:

// 傳入db_url,它期望返回一個SqliteQueryResult
async fn create_schema(db_url:&str) -> Result<SqliteQueryResult, sqlx::Error> {
    // 創建一個連接到db_url的連接池
    let pool = SqlitePool::connect(db_url).await?;

    // 定義數據庫表
    let qry = 
    "PRAGMA foreign_keys = ON;
    CREATE TABLE IF NOT EXISTS settings
    (
        settings_id     INTEGER PRIMARY KEY NOT NULL,
        description     TEXT                NOT NULL,
        created_on      DATETIME DEFAULT    (datetime('now', 'localtime')),
        updated_on      DATETIME DEFAULT    (datetime('now', 'localtime')),
        done            BOOLEAN             NOT NULL DEFAULT 0
    );
    CREATE TABLE IF NOT EXISTS project
    (
        project_id      INTEGER PRIMARY KEY AUTOINCREMENT,
        product_name    TEXT,
        created_on      DATETIME DEFAULT    (datetime('now', 'localtime')),
        updated_on      DATETIME DEFAULT    (datetime('now', 'localtime')),
        img_directory   TEXT     NOT NULL,
        out_directory   TEXT     NOT NULL,
        status          TEXT     NOT NULL,
        settings_id     INTEGER  NOT NULL DEFAULT 1,
        FOREIGN KEY (settings_id) REFERENCES settings (settings_id) ON UPDATE SET NULL ON DELETE SET NULL
    );";

    // 運行
    let result = sqlx::query(qry).execute(&pool).await;

    // 關閉連接池
    pool.close().await; 

    result
}

第三步,main 函數

async Main 函數是程序的異步入口點,它首先使用 Sqlite::database_exists 檢查數據庫是否存在,如果不存在,則使用 Sqlite::create_database 創建數據庫。然後,調用 create_schema 來設置數據庫模式。在模式創建之後,再次連接到數據庫,在 settings 表中插入一條 testing 記錄。

#[async_std::main]
async fn main() {
    // 在項目根目錄下創建一個數據庫名爲'sqlite.db'文件
    let db_url = String::from("sqlite://sqlite.db");

    // 如果數據庫不存在,則創建它。
    if !Sqlite::database_exists(&db_url).await.unwrap_or(false){
        Sqlite::create_database(&db_url).await.unwrap();

        //如果存在,則調用create_schema
        match create_schema(&db_url).await {
            // 如果一切順利,打印OK…否則panic
            Ok(_) => println!("database created succesfully"),
            Err(e) => panic!("{}", e)
        }
    }

    // 連接數據庫
    let instances = SqlitePool::connect(&db_url).await.unwrap();

    // 在settings表的description字段插入"testing"
    let qry = "INSERT INTO settings (description) VALUES($1)";
    let result = sqlx::query(qry).bind("testing").execute(&instances).await;

    // 關閉數據庫
    instances.close().await;
    println!("{:?}", result);
}

運行結果如下:

database created succesfully
Ok(SqliteQueryResult { changes: 1, last_insert_rowid: 1 })

注意

將 Rust 與 SQLite 集成僅僅是個開始,你可以嘗試執行不同的 sql 語句,深入瞭解 sqlx 及其功能。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/u6Heoqi4c28Uk5Sxp1kz0Q