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(())
}

这个增强版示例展示了:

  1. 使用WAL日志模式创建数据库连接
  2. 创建表结构
  3. 批量插入多条用户数据
  4. 查询符合条件的数据
  5. 更新数据记录
  6. 使用事务进行批量删除操作
  7. 获取剩余记录数量

代码中包含了详细的注释,说明了每个操作的作用和参数含义。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)
}

示例代码说明

  1. 数据库连接:使用WAL(Write-Ahead Logging)模式提高并发性能
  2. 表初始化:创建users表,包含id、name和age字段
  3. 数据插入
    • 单条插入:使用execute方法
    • 批量插入:使用事务+预编译语句提高性能
  4. 数据查询
    • 查询所有用户并按年龄降序排列
    • 条件查询:查询年龄大于指定值的用户
  5. 错误处理:使用Rust的Result类型进行错误处理

这个完整示例演示了如何使用async-sqlite进行常见的数据库操作,包括连接管理、CRUD操作、事务处理和预编译语句的使用。

回到顶部