Rust | SQLite 数据库 | rusqlite

更新于 2026-01-17

Mike Code 2025-02-25

SQLite 是一种基于文件的、无服务器的、零配置的、支持事务的、轻量级的、自包含且跨平台的数据库引擎。

(你也可以观看我的 YouTube 视频)

要安装 SQLite,我们可以使用 Homebrew,在终端中运行:

brew install sqlite

检查是否已成功安装 SQLite,可在终端中运行:

sqlite3 --version

在 Rust 中使用 SQLite,我们需要在 Cargo.toml 中添加依赖项:

[dependencies]
rusqlite = { version = "0.33.0", features = ["bundled"] }

main.rs 中:

use std::fs;

fn main() {
    let connection = rusqlite::Connection::open("test.db").unwrap();

    connection.execute("
        CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT, 
            name TEXT,
            score REAL
        )
    ", []).unwrap();

    
    connection.execute("INSERT INTO users (name, score) VALUES (?1, ?2)", [&"jim", &"9.8"]).unwrap();
    connection.execute("INSERT INTO users (name, score) VALUES (?1, ?2)", [&"pam", &"9.9"]).unwrap();

    let mut stat = connection.prepare("SELECT * FROM users").unwrap();
    let mut rows = stat.query([]).unwrap();

    while let Some(row) = rows.next().unwrap() {
        let id: i32 = row.get(0).unwrap();
        let name: String = row.get(1).unwrap();
        let score: f32 = row.get(2).unwrap(); 

        println!("id : {}, name: {}, score: {}", id, name, score)
    }

    fs::remove_file("test.db").unwrap();
}

我们调用 rusqlite::Connection::open 来打开数据库文件。如果当前目录下没有名为 test.db 的文件,它将在 Rust 项目文件夹中自动创建一个。该方法会返回一个包含连接的 Result,我们调用 unwrap() 来处理这个结果。

我们在连接上调用 execute 方法,创建一张名为 users 的表,并添加了 IF NOT EXISTS 约束,这意味着:如果已经存在名为 users 的表,则不会重复创建;如果不存在,则会新建一张表。

我们定义了三列:

  • 第一列为 id,类型为 INTEGER,并设置为主键(PRIMARY KEY)以确保其唯一性,同时加上 AUTOINCREMENT,这样该列的值会自动递增,我们无需手动插入数据。
  • 第二列为 name,类型为 TEXT(即字符串类型)。
  • 第三列为 score,类型为 REAL(即浮点数类型)。

execute 方法中,第二个参数是一个包含 SQL 参数的数组。由于创建表时不需要传入任何参数,因此我们传入一个空数组 []

接着,我们再次在连接上调用 execute 方法,向 users 表中插入数据。在第一个参数(SQL 语句)中,我们使用带整数编号的问号(如 ?1, ?2)作为占位符,用于引用第二个参数数组中的值。在第二个参数(参数数组)中,我们传入字符串字面量的引用作为实际参数。

我们向 users 表中插入了两条记录。

随后,我们在连接上调用 prepare 方法,准备一条可变的 SQL 语句,用于从 users 表中查询所有数据。接着在该语句上调用 query 方法,返回一个行迭代器 rows。我们使用 mut 关键字使其可变。

我们对 rows 调用 next 方法,逐行获取数据。该方法返回一个 Result<Option<Row>>,我们调用 unwrap() 处理 Result,并使用 while let 循环配合模式匹配来遍历每一行(当 Some(row) 存在时进行解构)。在循环体内,我们对每一行调用 get 方法,并传入列索引(从 0 开始)来获取各字段的值。同时,我们必须为每个变量显式标注类型。最后,我们将获取到的值打印出来。

最后,为了清理环境,我们只需调用 fs::remove_file 函数删除 .db 文件即可。