Rust实战:连接与操作SQLite数据库 – wiki大全

My apologies, I seem to be misinterpreting my available tools. I do not have a write_file or run_shell_command tool to create a file directly.

I will provide the article content directly in this response.

Here is the article you requested:

Rust实战:连接与操作SQLite数据库

Rust以其卓越的性能、内存安全和并发特性,在系统编程领域备受青睐。当需要一个轻量级、无需独立服务器的数据库解决方案时,SQLite通常是首选。本文将详细介绍如何在Rust项目中集成并操作SQLite数据库。

1. 项目设置

首先,创建一个新的Rust项目并添加必要的依赖。我们将使用 rusqlite crate,它是Rust社区中用于SQLite操作的流行库。

bash
cargo new rust_sqlite_app
cd rust_sqlite_app

打开 Cargo.toml 文件,在 [dependencies] 部分添加 rusqlite

toml
[dependencies]
rusqlite = "0.30.0" # 请检查 crates.io 获取最新版本

2. 连接到数据库

连接到SQLite数据库非常简单。如果数据库文件不存在,rusqlite 会自动创建它。

“`rust
use rusqlite::{Connection, Result};

fn main() -> Result<()> {
let conn = Connection::open(“my_database.db”)?;

println!("成功连接到SQLite数据库!");

// 后续操作将在这里进行

Ok(())

}
“`

Connection::open() 函数接收一个文件路径。如果路径是 :memory:,则会创建一个内存数据库,当连接关闭时数据会丢失。Result 类型用于错误处理,这是Rust中的常见模式。

3. 创建表格

连接成功后,下一步是创建数据库表。我们将创建一个 users 表。

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let conn = Connection::open(“my_database.db”)?;

conn.execute(
“CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE
)”,
(), // 空元组表示没有参数
)?;
println!(“表 ‘users’ 已创建或已存在。”);

Ok(())

}

“`

conn.execute() 方法用于执行不返回行的SQL语句,例如 CREATE TABLE, INSERT, UPDATE, DELETEIF NOT EXISTS 子句可以防止在表已存在时报错。

4. 插入数据

插入数据时,推荐使用参数化查询来防止SQL注入攻击。rusqlite 支持位置参数 (?1, ?2?)。

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let mut conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;

let name1 = “Alice”;
let email1 = “[email protected]”;
conn.execute(
“INSERT INTO users (name, email) VALUES (?1, ?2)”,
(name1, email1),
)?;
println!(“插入用户:{} ({})”, name1, email1);

let name2 = “Bob”;
let email2 = “[email protected]”;
conn.execute(
“INSERT INTO users (name, email) VALUES (?1, ?2)”,
(name2, email2),
)?;
println!(“插入用户:{} ({})”, name2, email2);

// 尝试插入一个重复的 email 会导致错误
match conn.execute(
“INSERT INTO users (name, email) VALUES (?1, ?2)”,
(“Charlie”, “[email protected]”),
) {
Ok(_) => println!(“插入用户:Charlie ([email protected])”),
Err(e) => println!(“插入 Charlie 失败:{}”, e),
}

Ok(())

}

“`

这里我们使用了 (name1, email1) 这样的元组来传递参数。rusqlite 会自动将Rust类型映射到对应的SQLite类型。

5. 查询数据

查询数据是数据库操作的核心。rusqlite 提供了几种查询方法:

查询单行数据

对于期望只返回一行数据的查询,可以使用 conn.query_row()

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Alice”, “[email protected]”),

)?;\n

struct User {
id: i32,
name: String,
email: String,
}

let user_id = 1;
let mut stmt = conn.prepare(“SELECT id, name, email FROM users WHERE id = ?1”)?;
let user = stmt.query_row([user_id], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
})
})?;

println!(“查询到用户:ID: {}, Name: {}, Email: {}”, user.id, user.name, user.email);

Ok(())

}

“`

query_row() 接受一个参数元组和一个闭包。闭包接收一个 Row 对象,你可以使用 row.get() 方法按索引或列名获取值。

查询多行数据

对于返回多行数据的查询,需要先 prepare() 语句,然后 query() 获取一个迭代器。

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Alice”, “[email protected]”),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Bob”, “[email protected]”),

)?;\n

struct User {
id: i32,
name: String,
email: String,
}

let mut stmt = conn.prepare(“SELECT id, name, email FROM users”)?;
let user_iter = stmt.query_map([], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
email: row.get(2)?,
})
})?;

println!(“所有用户:”);
for user_result in user_iter {
let user = user_result?;
println!(” ID: {}, Name: {}, Email: {}”, user.id, user.name, user.email);
}

Ok(())

}

“`

query_map() 同样接受参数和闭包,但它返回一个 Rows 迭代器,每个元素都是 Result<User>

6. 更新数据

更新数据同样使用 conn.execute()

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Alice”, “[email protected]”),

)?;\n

let new_name = “Alicia”;
let user_id_to_update = 1;
let affected_rows = conn.execute(
“UPDATE users SET name = ?1 WHERE id = ?2”,
(new_name, user_id_to_update),
)?;

println!(“更新了 {} 行。用户ID {} 的名称已更改为 {}”, affected_rows, user_id_to_update, new_name);

Ok(())

}

“`

execute() 返回受影响的行数。

7. 删除数据

删除数据也是通过 conn.execute() 完成的。

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Alice”, “[email protected]”),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Bob”, “[email protected]”),

)?;\n

let user_id_to_delete = 2;
let affected_rows = conn.execute(
“DELETE FROM users WHERE id = ?1”,
[user_id_to_delete],
)?;

println!(“删除了 {} 行。用户ID {} 已删除。”, affected_rows, user_id_to_delete);

Ok(())

}

“`

8. 错误处理

rusqlite 中的所有操作都返回 rusqlite::Result 类型,它是一个 Result<T, rusqlite::Error> 的别名。你可以使用 ? 操作符进行错误传播,或者使用 match 语句进行更细致的错误处理。

例如,尝试插入重复的 UNIQUE 字段会返回一个 Error

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;

conn.execute(

“INSERT INTO users (name, email) VALUES (?1, ?2)”,

(“Alice”, “[email protected]”),

)?;\n

let res = conn.execute(
“INSERT INTO users (name, email) VALUES (?1, ?2)”,
(“David”, “[email protected]”),
);

match res {
Ok(rows_affected) => println!(“插入了 {} 行。”, rows_affected),
Err(e) => {
eprintln!(“插入失败: {}”, e);
// 可以根据错误的类型进行更详细的处理
if let rusqlite::Error::SqliteFailure(err, Some(msg)) = e {
if err.code == rusqlite::ErrorCode::ConstraintViolation {
eprintln!(“违反唯一约束: {}”, msg);
}
}
}
}

Ok(())

}

“`

9. 事务处理

事务是确保数据库操作原子性、一致性、隔离性、持久性(ACID)的关键。rusqlite 支持事务。

“`rust

use rusqlite::{Connection, Result};

fn main() -> Result<()> {

let mut conn = Connection::open(“my_database.db”)?;

conn.execute(

“CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT NOT NULL,

email TEXT NOT NULL UNIQUE

)”,

(),

)?;\n

let tx = conn.transaction()?; // 开始一个事务

tx.execute(“INSERT INTO users (name, email) VALUES (?1, ?2)”, (“Frank”, “[email protected]”))?;
tx.execute(“INSERT INTO users (name, email) VALUES (?1, ?2)”, (“Grace”, “[email protected]”))?;

// 假设这里发生了一个错误,事务会被回滚
// tx.execute(“INSERT INTO users (name, email) VALUES (?1, ?2)”, (“ErrorUser”, “[email protected]”))?;

tx.commit()?; // 提交事务

println!(“事务提交成功,Frank 和 Grace 已插入。”);

Ok(())

}

“`

如果 tx.execute() 中的任何一个操作失败,事务会自动回滚,之前的更改将不会被保存。

总结

本文介绍了如何在Rust中使用 rusqlite crate 连接和操作SQLite数据库,包括:

  • 添加 rusqlite 依赖
  • 建立数据库连接
  • 创建数据表
  • 使用参数化查询插入数据
  • 查询单行和多行数据
  • 更新和删除数据
  • 基本的错误处理
  • 使用事务保证数据一致性

rusqlite 提供了一个类型安全且符合Rust习惯的API,是Rust应用与SQLite交互的强大工具。通过这些基础知识,您可以开始构建自己的Rust应用程序,利用SQLite进行本地数据存储。

进一步学习

滚动至顶部