Rust数据库连接库libsql-hrana的使用:支持高性能SQLite操作与异步查询的Hrana协议实现

Rust数据库连接库libsql-hrana的使用:支持高性能SQLite操作与异步查询的Hrana协议实现

安装

在项目目录中运行以下Cargo命令:

cargo add libsql-hrana

或者在Cargo.toml中添加以下行:

libsql-hrana = "0.9.19"

示例代码

以下是使用libsql-hrana进行SQLite操作的完整示例:

use libsql_hrana::client::{Client, Config};
use tokio::runtime::Runtime;

async fn async_query() -> Result<(), Box<dyn std::error::Error>> {
    // 创建客户端配置
    let config = Config::new("http://localhost:8080") // 替换为你的Hrana服务器地址
        .auth_token("your-auth-token"); // 如果需要认证
    
    // 创建客户端
    let client = Client::new(config).await?;
    
    // 创建连接
    let conn = client.open().await?;
    
    // 执行查询
    let stmt = conn.prepare("SELECT * FROM users WHERE id = ?").await?;
    let rows = stmt.query([1]).await?;
    
    // 处理结果
    while let Some(row) = rows.next().await? {
        let id: i64 = row.get(0)?;
        let name: String = row.get(1)?;
        println!("User: id={}, name={}", id, name);
    }
    
    Ok(())
}

fn main() {
    // 创建Tokio运行时
    let rt = Runtime::new().unwrap();
    
    // 运行异步查询
    rt.block_on(async_query()).unwrap();
}

特性说明

  1. 高性能SQLite操作:通过Hrana协议实现高效的SQLite数据库访问
  2. 异步支持:完全基于异步I/O设计,适合高并发场景
  3. 预编译语句:支持参数化查询和预编译语句
  4. 连接池:内置连接池管理,提高连接复用率

完整示例demo

use libsql_hrana::client::{Client, Config};
use tokio::runtime::Runtime;

async fn demo() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 配置客户端
    let config = Config::new("http://localhost:8080")
        .auth_token("your-secret-token");
    
    // 2. 创建客户端
    let client = Client::new(config).await?;
    
    // 3. 获取数据库连接
    let conn = client.open().await?;
    
    // 4. 创建表
    conn.execute(
        "CREATE TABLE IF NOT EXISTS products (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            price REAL
        )"
    ).await?;
    
    // 5. 插入数据
    let insert_stmt = conn.prepare(
        "INSERT INTO products (name, price) VALUES (?, ?)"
    ).await?;
    
    insert_stmt.execute(["Rust Book", 39.99]).await?;
    insert_stmt.execute(["TypeScript Guide", 29.99]).await?;
    
    // 6. 查询数据
    let query_stmt = conn.prepare(
        "SELECT id, name, price FROM products WHERE price > ?"
    ).await?;
    
    let rows = query_stmt.query([30.0]).await?;
    
    // 7. 处理结果
    while let Some(row) = rows.next().await? {
        let id: i64 = row.get(0)?;
        let name: String = row.get(1)?;
        let price: f64 = row.get(2)?;
        
        println!("Product: id={}, name={}, price={:.2}", id, name, price);
    }
    
    Ok(())
}

fn main() {
    let rt = Runtime::new().unwrap();
    rt.block_on(demo()).unwrap();
}

所有者

  • tursodatabase/publish团队
  • Pekka Enberg (@penberg)

许可证

MIT License


1 回复

Rust数据库连接库libsql-hrana的使用:支持高性能SQLite操作与异步查询的Hrana协议实现

介绍

libsql-hrana是一个Rust实现的Hrana协议客户端库,用于与SQLite数据库进行高性能交互。Hrana协议是由Turso(原libSQL)团队开发的专有协议,提供了比传统SQLite接口更好的性能和异步支持。

主要特点:

  • 支持异步/await语法
  • 高性能的SQLite操作
  • 兼容标准SQLite语法
  • 支持批量操作
  • 提供连接池管理

安装方法

在Cargo.toml中添加依赖:

[dependencies]
libsql-hrana = "0.1"
tokio = { version = "1.0", features = ["full"] }

基本使用方法

1. 建立连接

use libsql_hrana::client::{Client, Config};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = Config {
        url: "libsql://your-database.turso.io".to_string(),
        auth_token: Some("your-auth-token".to_string()),
    };
    
    let client = Client::connect(config).await?;
    
    Ok(())
}

2. 执行查询

// 同步查询
let rows = client.execute("SELECT * FROM users WHERE age > ?", [18]).await?;
for row in rows {
    let id: i64 = row.get(0)?;
    let name: String = row.get(1)?;
    println!("id: {}, name: {}", id, name);
}

// 异步流式查询
let mut stmt = client.prepare("SELECT * FROM posts ORDER BY created_at DESC").await?;
let mut rows = stmt.query([]).await?;
while let Some(row) = rows.next().await? {
    let title: String = row.get("title")?;
    println!("Post title: {}", title);
}

3. 事务处理

let tx = client.transaction().await?;

tx.execute("INSERT INTO logs (message) VALUES (?)", ["Transaction started"]).await?;
tx.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1", []).await?;
tx.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2", []).await?;

tx.commit().await?;

高级用法

批量操作

let batch = client.batch();
batch.execute("INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "alice@example.com"]);
batch.execute("INSERT INTO users (name, email) VALUES (?, ?)", ["Bob", "bob@example.com"]);

let results = batch.commit().await?;
println!("Inserted {} rows", results.len());

连接池

use libsql_hrana::pool::Pool;

let pool = Pool::new(Config {
    url: "libsql://your-database.turso.io".to_string(),
    auth_token: Some("your-auth-token".to_string()),
}, 5); // 最大5个连接

let conn = pool.get().await?;
let rows = conn.execute("SELECT COUNT(*) FROM users", []).await?;

性能优化技巧

  1. 使用预编译语句重复查询:
let stmt = client.prepare("SELECT * FROM products WHERE category = ?").await?;

// 多次使用同一个预编译语句
let tech_products = stmt.query(["technology"]).await?;
let food_products = stmt.query(["food"]).await?;
  1. 批量插入数据时使用事务:
let tx = client.transaction().await?;
for i in 0..1000 {
    tx.execute("INSERT INTO metrics (value) VALUES (?)", [i]).await?;
}
tx.commit().await?;

错误处理

match client.execute("SELECT * FROM non_existent_table", []).await {
    Ok(rows) => {
        // 处理结果
    },
    Err(libsql_hrana::Error::ApiError(e)) => {
        eprintln!("API error: {}", e.message);
    },
    Err(e) => {
        eprintln!("Other error: {}", e);
    }
}

注意事项

  1. Hrana协议需要服务端支持,不能直接连接本地SQLite文件
  2. 生产环境建议使用连接池管理连接
  3. 敏感操作务必使用事务保证数据一致性
  4. 注意处理网络错误和重连逻辑

libsql-hrana为Rust开发者提供了现代化的SQLite操作方式,特别适合云原生环境下的数据库操作需求。

完整示例代码

use libsql_hrana::{
    client::{Client, Config},
    pool::Pool,
};
use tokio;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // 1. 创建连接配置
    let config = Config {
        url: "libsql://your-database.turso.io".to_string(),
        auth_token: Some("your-auth-token".to_string()),
    };

    // 2. 创建连接池
    let pool = Pool::new(config, 5); // 最大5个连接
    
    // 3. 从连接池获取连接
    let conn = pool.get().await?;
    
    // 4. 创建表
    conn.execute(
        "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)",
        [],
    )
    .await?;

    // 5. 插入数据
    let tx = conn.transaction().await?;
    tx.execute("INSERT INTO users (name, age) VALUES (?, ?)", ["Alice", 25])
        .await?;
    tx.execute("INSERT INTO users (name, age) VALUES (?, ?)", ["Bob", 30])
        .await?;
    tx.commit().await?;

    // 6. 预编译查询语句
    let stmt = conn
        .prepare("SELECT id, name, age FROM users WHERE age > ?")
        .await?;

    // 7. 执行查询
    let mut rows = stmt.query([18]).await?;
    while let Some(row) = rows.next().await? {
        let id: i64 = row.get(0)?;
        let name: String = row.get(1)?;
        let age: i64 = row.get(2)?;
        println!("User - id: {}, name: {}, age: {}", id, name, age);
    }

    // 8. 批量操作
    let batch = conn.batch();
    batch.execute("UPDATE users SET age = age + 1 WHERE name = ?", ["Alice"]);
    batch.execute("UPDATE users SET age = age + 1 WHERE name = ?", ["Bob"]);
    let _ = batch.commit().await?;

    // 9. 错误处理示例
    match conn.execute("SELECT * FROM non_existent_table", []).await {
        Ok(rows) => {
            println!("Query successful, got {} rows", rows.len());
        }
        Err(libsql_hrana::Error::ApiError(e)) => {
            eprintln!("API error occurred: {}", e.message);
        }
        Err(e) => {
            eprintln!("Other error occurred: {}", e);
        }
    }

    Ok(())
}

这个完整示例演示了:

  1. 创建连接池
  2. 执行DDL语句创建表
  3. 使用事务插入数据
  4. 预编译SQL语句并执行查询
  5. 批量更新操作
  6. 错误处理机制

要运行这个示例,需要确保:

  1. 已配置正确的数据库URL和认证令牌
  2. 项目中已添加libsql-hrana和tokio依赖
  3. 运行在支持async/await的Rust环境(1.45+)
回到顶部