Rust数据库连接池库deadpool-sqlite的使用:高效管理SQLite连接和异步操作

Rust数据库连接池库deadpool-sqlite的使用:高效管理SQLite连接和异步操作

Deadpool是一个简单高效的异步连接池库,用于管理各种类型的连接和对象。deadpool-sqlite是专门为SQLite数据库设计的连接池实现,它基于rusqlite库并提供了线程安全的连接管理。

特性

特性 描述 额外依赖 默认启用
rt_tokio_1 支持tokio运行时 deadpool/rt_tokio_1
rt_async-std_1 支持async-std运行时 deadpool/rt_async-std_1
serde 支持serde序列化 deadpool/serde, serde/derive
tracing 支持tracing日志追踪 deadpool-sync/tracing, tracing

示例代码

use deadpool_sqlite::{Config, Runtime};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut cfg = Config::new("db.sqlite3");
    let pool = cfg.create_pool(Runtime::Tokio1).unwrap();
    let conn = pool.get().await.unwrap();
    let result: i64 = conn
        .interact(|conn| {
            let mut stmt = conn.prepare("SELECT 1")?;
            let mut rows = stmt.query([])?;
            let row = rows.next()?.unwrap();
            row.get(0)
        })
        .await??;
    assert_eq!(result, 1);
    Ok(())
}

完整示例Demo

use deadpool_sqlite::{Config, Runtime};
use tokio::task;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建连接池配置
    let mut cfg = Config::new("example.db");
    
    // 设置连接池大小
    cfg.pool.max_size = 16;
    
    // 创建连接池 (使用Tokio运行时)
    let pool = cfg.create_pool(Runtime::Tokio1)?;
    
    // 创建表
    init_db(&pool).await?;
    
    // 并发插入数据
    let tasks: Vec<_> = (0..10)
        .map(|i| {
            let pool = pool.clone();
            task::spawn(async move {
                let conn = pool.get().await?;
                conn.interact(move |conn| {
                    conn.execute(
                        "INSERT INTO users (name, age) VALUES (?1, ?2)",
                        [format!("User {}", i), i.to_string()],
                    )
                })
                .await?
            })
        })
        .collect();
    
    // 等待所有插入任务完成
    for task in tasks {
        task.await??;
    }
    
    // 查询数据
    let conn = pool.get().await?;
    let users: Vec<(String, i32)> = conn
        .interact(|conn| {
            let mut stmt = conn.prepare("SELECT name, age FROM users")?;
            let rows = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?;
            rows.collect::<Result<Vec<_>, _>>()
        })
        .await??;
    
    println!("Users: {:?}", users);
    Ok(())
}

async fn init_db(pool: &deadpool_sqlite::Pool) -> Result<(), Box<dyn std::error::Error>> {
    let conn = pool.get().await?;
    conn.interact(|conn| {
        conn.execute_batch(
            "BEGIN;
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                age INTEGER NOT NULL
            );
            COMMIT;",
        )
    })
    .await??;
    Ok(())
}

许可证

deadpool-sqlite采用以下任一种许可证:

  • Apache License, Version 2.0
  • MIT license

安装

要在项目中使用deadpool-sqlite,可以运行以下Cargo命令:

cargo add deadpool-sqlite

或者在Cargo.toml中添加:

deadpool-sqlite = "0.12.1"

这个库提供了高效的SQLite连接管理,特别适合在异步环境中使用SQLite数据库的场景。通过连接池可以避免频繁创建和销毁连接的开销,提高应用程序性能。


1 回复

Rust数据库连接池库deadpool-sqlite的使用:高效管理SQLite连接和异步操作

完整示例demo

下面是一个完整的示例,展示了如何使用deadpool-sqlite进行数据库操作:

use deadpool_sqlite::{Config, Pool, Runtime};
use rusqlite::params;
use tokio::task;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 创建连接池配置
    let config = Config::new("example.db")
        .with_pool_size(5)  // 设置最大连接数为5
        .with_timeout(Some(10));  // 设置获取连接超时时间为10秒
    
    // 2. 创建连接池
    let pool = config.create_pool(Runtime::Tokio1)?;
    
    // 3. 创建测试表
    create_table(&pool).await?;
    
    // 4. 插入数据
    insert_user(&pool, "Alice").await?;
    insert_user(&pool, "Bob").await?;
    
    // 5. 查询数据
    query_users(&pool).await?;
    
    // 6. 更新数据
    update_user(&pool, 1, "Alice Smith").await?;
    
    // 7. 再次查询验证更新
    query_users(&pool).await?;
    
    Ok(())
}

async fn create_table(pool: &Pool) -> Result<(), Box<dyn std::error::Error>> {
    let conn = pool.get().await?;
    conn.execute(
        "CREATE TABLE IF NOT EXISTS users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL
        )",
        [],
    )?;
    Ok(())
}

async fn insert_user(pool: &Pool, name: &str) -> Result<(), Box<dyn std::error::Error>> {
    let conn = pool.get().await?;
    let mut stmt = conn.prepare("INSERT INTO users (name) VALUES (?)")?;
    stmt.execute(params![name])?;
    println!("Inserted user: {}", name);
    Ok(())
}

async fn query_users(pool: &Pool) -> Result<(), Box<dyn std::error::Error>> {
    let conn = pool.get().await?;
    let mut stmt = conn.prepare("SELECT id, name FROM users")?;
    let rows = stmt.query_map([], |row| {
        Ok((row.get::<_, i32>(0)?, row.get::<_, String>(1)?))
    })?;
    
    println!("Current users:");
    for row in rows {
        let (id, name) = row?;
        println!("  {}: {}", id, name);
    }
    Ok(())
}

async fn update_user(
    pool: &Pool,
    user_id: i32,
    new_name: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let conn = pool.get().await?;
    let tx = conn.transaction()?;
    
    tx.execute(
        "UPDATE users SET name = ? WHERE id = ?",
        params![new_name, user_id],
    )?;
    
    tx.commit()?;
    println!("Updated user {} to {}", user_id, new_name);
    Ok(())
}

async fn async_insert(pool: Pool) -> Result<(), Box<dyn std::error::Error>> {
    task::spawn_blocking(move || {
        let conn = pool.get()?;
        let mut stmt = conn.prepare("INSERT INTO users (name) VALUES (?)")?;
        stmt.execute(params!["Async User"])?;
        Ok(())
    })
    .await??;
    
    println!("Inserted user via async task");
    Ok(())
}

这个完整示例演示了:

  1. 创建连接池并进行配置
  2. 创建数据库表
  3. 基本的CRUD操作
  4. 事务处理
  5. 异步操作

运行此程序前,请确保:

  1. 已添加正确的依赖到Cargo.toml
  2. 对数据库文件有读写权限
  3. 使用支持异步的Rust运行时(如tokio)
回到顶部