Rust异步SQLite数据库驱动async-sqlite的使用,高效支持异步读写和轻量级SQLite操作
根据提供的内容,我将整理关于async-sqlite库的使用信息。以下是完整的示例代码:
use async_sqlite::{ClientBuilder, JournalMode};
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
// 创建或打开SQLite数据库
// 使用WAL日志模式提高并发性能
let client = ClientBuilder::new()
.path("example.db") // 数据库文件路径
.journal_mode(JournalMode::Wal) // 设置WAL日志模式
.open()
.await?; // 异步打开数据库连接
// 创建表(如果不存在)
client.conn(|conn| {
conn.execute(
// 创建users表,包含id(主键)、name和age字段
"CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER
)",
[], // 无参数
)
}).await?;
// 插入多条用户数据
let users = vec![
("Alice", 30),
("Bob", 25),
("Charlie", 35),
("David", 28)
];
for (name, age) in users {
client.conn(|conn| {
conn.execute(
"INSERT INTO users (name, age) VALUES (?1, ?2)",
[name, age], // 绑定参数
)
}).await?;
}
// 查询年龄大于25的用户
let names: Vec<String> = client.conn(|conn| {
let mut stmt = conn.prepare("SELECT name FROM users WHERE age > ?")?;
let rows = stmt.query_map([25], |row| row.get(0))?;
rows.collect::<Result<Vec<_>, _>>()
}).await?;
println!("Users older than 25:");
for name in names {
println!("- {}", name);
}
// 更新数据
client.conn(|conn| {
conn.execute(
"UPDATE users SET age = ? WHERE name = ?",
[31, "Alice"], // 将Alice的年龄更新为31
)
}).await?;
// 事务操作示例
client.conn(|conn| {
let tx = conn.transaction()?; // 开始事务
tx.execute("DELETE FROM users WHERE age < ?", [30])?;
tx.commit() // 提交事务
}).await?;
// 获取剩余用户数量
let count: i64 = client.conn(|conn| {
conn.query_row("SELECT COUNT(*) FROM users", [], |row| row.get(0))
}).await?;
println!("Total users after deletion: {}", count);
Ok(())
}
这个增强版示例展示了:
- 使用WAL日志模式创建数据库连接
- 创建表结构
- 批量插入多条用户数据
- 查询符合条件的数据
- 更新数据记录
- 使用事务进行批量删除操作
- 获取剩余记录数量
代码中包含了详细的注释,说明了每个操作的作用和参数含义。async-sqlite库通过将SQLite操作封装在异步上下文中,使得可以在Rust的async/await生态中高效地使用SQLite数据库。
关键技术点:
- 使用
ClientBuilder
创建数据库连接 - 通过
conn()
方法在异步上下文中执行同步数据库操作 - 支持参数化查询防止SQL注入
- 提供事务支持保证数据一致性
- 兼容各种异步运行时(如tokio、async-std等)
1 回复
Rust异步SQLite数据库驱动async-sqlite的使用指南
简介
async-sqlite
是一个Rust异步SQLite数据库驱动,专为现代异步Rust应用程序设计。它提供了高效的非阻塞SQLite操作,特别适合需要轻量级嵌入式数据库的异步应用场景。
主要特性
- 完全异步支持(基于tokio)
- 轻量级实现
- 线程安全
- 支持预编译语句
- 事务支持
- 低开销
安装
在Cargo.toml中添加依赖:
[dependencies]
async-sqlite = "0.2"
tokio = { version = "1.0", features = ["full"] }
基本使用方法
1. 打开数据库连接
use async_sqlite::rusqlite::params;
use async_sqlite::JournalMode;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 打开或创建数据库
let conn = async_sqlite::open("test.db")
.journal_mode(JournalMode::Wal) // 使用WAL模式提高并发性能
.open()
.await?;
Ok(())
}
2. 执行SQL语句
// 创建表
conn.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)", ())
.await?;
// 插入数据
conn.execute(
"INSERT INTO users (name, age) VALUES (?1, ?2)",
params!["Alice", 30],
)
.await?;
3. 查询数据
// 查询单行
let row = conn.query_row("SELECT name, age FROM users WHERE id = ?", [1], |row| {
Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?))
})
.await?;
println!("User: {:?}", row);
// 查询多行
let mut stmt = conn.prepare("SELECT id, name, age FROM users").await?;
let rows = stmt.query_map([], |row| {
Ok((row.get::<_, i32极为抱歉,我的回答被截断了。以下是完整的响应:
# Rust异步SQLite数据库驱动async-sqlite的使用指南
## 完整示例代码
```rust
use async_sqlite::{rusqlite::params, JournalMode};
use serde::Serialize;
#[derive(Debug, Serialize)]
struct User {
id: i32,
name: String,
age: i32,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 打开数据库连接(使用WAL模式提高性能)
let conn = async_sqlite::open("users.db")
.journal_mode(JournalMode::Wal)
.open()
.await?;
// 2. 初始化数据库表
init_db(&conn).await?;
// 3. 添加示例用户数据
add_user(&conn, "张三", 28).await?;
add_user(&conn, "李四", 32).await?;
add_user(&conn, "王五", 25).await?;
// 4. 批量插入用户数据
batch_insert_users(&conn).await?;
// 5. 查询并打印所有用户
let users = get_all_users(&conn).await?;
println!("所有用户:");
for user in users {
println!("ID: {}, 姓名: {}, 年龄: {}", user.id, user.name, user.age);
}
// 6. 查询特定年龄段的用户
let adult_users = get_users_older_than(&conn, 30).await?;
println!("\n30岁以上的用户:");
for user in adult_users {
println!("ID: {}, 姓名: {}", user.id, user.name);
}
Ok(())
}
/// 初始化数据库表
async fn init_db(conn: &async_sqlite::Connection) -> Result<(), Box<dyn std::error::Error>> {
conn.execute(
"CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER
)",
(),
)
.await?;
Ok(())
}
/// 添加单个用户
async fn add_user(conn: &async_sqlite::Connection, name: &str, age: i32) -> Result<(), Box<dyn std::error::Error>> {
conn.execute(
"INSERT INTO users (name, age) VALUES (?1, ?2)",
params![name, age],
)
.await?;
Ok(())
}
/// 批量插入用户数据(使用事务提高性能)
async fn batch_insert_users(conn: &async_sqlite::Connection) -> Result<(), Box<dyn std::error::Error>> {
let tx = conn.transaction().await?;
// 准备预编译语句
let mut stmt = tx.prepare("INSERT INTO users (name, age) VALUES (?, ?)").await?;
// 批量插入10个用户
for i in 1..=10 {
stmt.execute(params![format!("批量用户{}", i), 20 + i]).await?;
}
tx.commit().await?;
Ok(())
}
/// 获取所有用户
async fn get_all_users(conn: &async_sqlite::Connection) -> Result<Vec<User>, Box<dyn std::error::Error>> {
let mut stmt = conn.prepare("SELECT id, name, age FROM users ORDER BY age DESC").await?;
let users = stmt.query_map([], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
age: row.get(2)?,
})
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(users)
}
/// 获取年龄大于指定值的用户
async fn get_users_older_than(conn: &async_sqlite::Connection, min_age: i32) -> Result<Vec<User>, Box<dyn std::error::Error>> {
let mut stmt = conn.prepare("SELECT id, name FROM users WHERE age > ?").await?;
let users = stmt.query_map([min_age], |row| {
Ok(User {
id: row.get(0)?,
name: row.get(1)?,
age: min_age, // 这里为了简化没有查询age字段
})
})?
.collect::<Result<Vec<_>, _>>()?;
Ok(users)
}
示例代码说明
- 数据库连接:使用WAL(Write-Ahead Logging)模式提高并发性能
- 表初始化:创建users表,包含id、name和age字段
- 数据插入:
- 单条插入:使用
execute
方法 - 批量插入:使用事务+预编译语句提高性能
- 单条插入:使用
- 数据查询:
- 查询所有用户并按年龄降序排列
- 条件查询:查询年龄大于指定值的用户
- 错误处理:使用Rust的
Result
类型进行错误处理
这个完整示例演示了如何使用async-sqlite
进行常见的数据库操作,包括连接管理、CRUD操作、事务处理和预编译语句的使用。