在Rust中使用SQLX集成SQLite数据库

397次阅读  |  发布于6月以前

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及其功能。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8