rust语言学习笔记——Turso库(读写SQLite的库)

Turso简介

SQLite的下一步发展:一款专为Rust语言设计的、具有高性能且与SQLite兼容的数据库。

一、Turso特点

  • 兼容SQLite:其接口与rusqlite类似,拥有熟悉的API;不同之处在于它使用的是异步Rust语言。
  • Sqlite同时只能一个写操作,Turso可以并发写操作。
  • 高性能:采用Rust语言开发,以实现极致的速度与效率
  • 支持异步/等待机制:具备tokio支持的原生异步操作功能
  • 处理中:无需网络开销,可直接在应用程序中运行。
  • 跨平台:支持Linux、macOS和Windows系统
  • 事务支持:具备回滚功能的全ACID事务支持
  • 预处理语句:通过参数绑定实现高效的查询执行
  • 云同步:通过Builder::new_remote()与Turso Cloud实现同步(可选的sync功能)

二、安装

将其添加到你的Cargo.toml中:

toml 复制代码
[dependencies]
turso = "0.6.1"
tokio = { version = "1.52", features = ["full"] }

三、内存数据库案例

rust 复制代码
use turso::Builder;

#[tokio::main]
async fn main() -> turso::Result<()> {
    // 创建一个内存数据库数据库连接
    let db = Builder::new_local(":memory:").build().await?;
    let conn = db.connect()?; // 连接数据库

    // 创建一个表
    conn.execute(
        "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)",
        (),
    )
    .await?;

    // 插入数据到表
    conn.execute(
        "INSERT INTO users (name, email) VALUES (?1, ?2)",
        ["Alice", "alice@example.com"],
    )
    .await?;

    conn.execute(
        "INSERT INTO users (name, email) VALUES (?1, ?2)",
        ["Bob", "bob@example.com"],
    )
    .await?;

    // 查询表中的数据
    let mut rows = conn.query("SELECT * FROM users", ()).await?;

    while let Some(row) = rows.next().await? {
        let id = row.get_value(0)?;
        let name = row.get_value(1)?;
        let email = row.get_value(2)?;
        println!(
            "用户id: {},用户名:{},邮箱:{}",
            id.as_integer().unwrap_or(&0),
            name.as_text().unwrap_or(&"".to_string()),
            email.as_text().unwrap_or(&"".to_string())
        );
    }

    Ok(())
}

四、文件的数据库案例

rust 复制代码
use turso::{Builder, params};

#[tokio::main]
async fn main() -> turso::Result<()> {
    // new_local 按照路径构建一个基本的数据库参数对象;build 根据数据库参数对象创建数据库并打开,connect 连接数据库
    let db = Builder::new_local("my-database.db").build().await?;
    let conn = db.connect()?;

    // 创建一个表
    conn.execute(
        r#"CREATE TABLE IF NOT EXISTS posts (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            content TEXT,
            f_test REAL,   --浮点数据
            b_test BLOB,   --二进制数据
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )"#,
        (),
    )
    .await?;

    let f_test = 16.55555555225;
    let b_test = "hello world".as_bytes().to_vec();
    // 插入一条数据, 并返回影响的行数
    let rows_affected = conn
        .execute(
            "INSERT INTO posts (title, content, f_test, b_test) VALUES (?1, ?2, ?3, ?4)",
            params!["我的第一个帖子", "这是我的第一个帖子", f_test, b_test],
        )
        .await?;

    println!("插入 {} 行数据", rows_affected);
    println!("-----------------");

    // 查询所有数据, 并返回查询结果
    let mut rows = conn.query("SELECT * FROM posts", ()).await?;

    // 遍历查询结果, 并打印每个字段的值
    while let Some(row) = rows.next().await? {
        println!("帖子id: {}", row.get_value(0)?.as_integer().unwrap_or(&0));
        println!(
            "标题: {}",
            row.get_value(1)?.as_text().unwrap_or(&"".to_string())
        );
        println!(
            "内容: {}",
            row.get_value(2)?.as_text().unwrap_or(&"".to_string())
        );
        println!("浮点数据: {}", row.get_value(3)?.as_real().unwrap_or(&0.0));
        println!(
            "二进制数据: {:?}",
            row.get_value(4)?.as_blob().unwrap_or(&Vec::new())
        );
        println!(
            "发帖时间: {:?}",
            row.get_value(5)?.as_text().unwrap_or(&"".to_string())
        );
        println!("-----------------");
    }
    Ok(())
}

五、创建新数据库

rust 复制代码
let db = Builder::new_local(":memory:").build().await?;   // 内存数据库
let db = Builder::new_local("data.db").build().await?;    // 本地数据库

六、执行SQL语句

rust 复制代码
// 直接执行SQL
let rows_affected = conn.execute("INSERT INTO users (name) VALUES (?1)", ["Alice"]).await?;

// 多行查询
let mut rows = conn.query("SELECT * FROM users WHERE age > ?1", [18]).await?;

// sql预编译,然后执行预编译查询
let mut stmt = conn.prepare("SELECT * FROM users WHERE id = ?1").await?;
// 执行预编译查询
let mut rows = stmt.query([42]).await?;

// 执行预编译语句
let rows_affected = stmt.execute(["Alice"]).await?;

七、插入的数据

  • ["aaa","bbb"],只能是同一种数据类型
  • params!["aaa", 22, 2.2],可以不同的数据类型

八、数据集相关操作rows

  • rows.next() -> Result<Option<Row>>:获取下一行数据
  • rows.column_count() -> usize:获取字段数量
  • rows.column_name(idx: usize) -> Result<String> :根据索引获取字段名
  • rows.column_names() -> Vec<String>:获取所有字段名
  • rows.column_index(name: &str) -> Result<usize>:根据字段名获取结果的索引
  • rows.columns() -> Vec<Column>:获取查询结果的:字段名+类型,Column{name: String, decl_type: Option<String>}

九、数据行相关操作row

  • row.get_value(index: usize) -> Result<Value>:根据索引获取值
    • let title = row.get_value(1)?.as_text().unwrap_or(&"".to_string()):获取字段值转换为相应类型,空值设置为空字符串
  • row.get<T>(idx: usize) -> Result<T>:根据索引获取查询结果的字段值
    • let title = row.get::<String>(1)?:根据类型获取字段值
  • row.column_count() -> usize:获取字段数量

十、值相关操作Value

1、Value的定义

rust 复制代码
pub enum Value {
    Null,             // 空值
    Integer(i64),     // 整型
    Real(f64),        // 浮点型
    Text(String),     // 字符串
    Blob(Vec<u8>),    // 二进制
}

2、Value值的判断

  • Value.is_null() -> bool,值是否为空
  • Value.is_integer(&self) -> bool,值是否为i64
  • Value.is_real(&self) -> bool,值是否为f64
  • Value.is_text(&self) -> bool,值是否为String
  • Value.is_blob(&self) -> bool,值是否为Vec<u8>

3、Value值的转换

  • Value.as_integer() -> Option<&i64>
  • Value.as_real() -> Option<&f64>
  • Value.as_text() -> Option<&String>
  • Value.as_blob() -> Option<&Vec<u8>>

4、空值处理

  • .unwrap_or(&0),整型

  • .unwrap_or(&0.0),浮点型

  • .unwrap_or(&"".to_string()),字符串

  • .unwrap_or(&Vec::new()),二进制