Rust数据库操作库serde_rusqlite的使用:支持SQLite与Serde的高效序列化与反序列化

Rust数据库操作库serde_rusqlite的使用:支持SQLite与Serde的高效序列化与反序列化

简介

serde_rusqlite是一个提供便捷函数来桥接serde和rusqlite的库。它允许你将rusqlite::Row反序列化为serde::Deserialize类型,并将实现serde::Serialize的类型序列化为rusqlite期望的绑定查询参数(位置参数或命名参数)。

安装

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

cargo add serde_rusqlite

或者在Cargo.toml中添加:

[dependencies]
serde_rusqlite = "0.40.0"

特性

  • 命名绑定参数只支持从struct和map序列化
  • 位置绑定参数只支持从tuple、sequence和非可迭代的原始类型序列化
  • SQLite支持5种类型:NULL、INTEGER、REAL、TEXT和BLOB
  • 特殊类型处理:
    • u64如果无法表示为i64会失败
    • 简单enum会序列化为字符串
    • bool序列化为INTEGER 0或1
    • f64和f32的NaN值序列化为NULL
    • serde_bytes::Bytes和serde_bytes::ByteBuf作为处理BLOB的优化方式
    • unit序列化为NULL
    • 只有[u8]序列会使用BLOB数据库类型
    • unit_struct序列化为struct名称作为TEXT

示例代码

use serde_derive::{Deserialize, Serialize};
use serde_rusqlite::*;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct Example {
    id: i64,
    name: String,
}

fn main() -> rusqlite::Result<()> {
    // 创建内存数据库和表
    let connection = rusqlite::Connection::open_in_memory()?;
    connection.execute("CREATE TABLE example (id INT, name TEXT)", []).unwrap();

    // 使用结构体生成命名绑定查询参数
    let row1 = Example { id: 1, name: "first name".into() };
    connection.execute(
        "INSERT INTO example (id, name) VALUES (:id, :name)", 
        to_params_named(&row1).unwrap().to_slice().as_slice()
    )?;

    // 使用元组生成位置绑定查询参数
    let row2 = (2, "second name");
    connection.execute(
        "INSERT INTO example (id, name) VALUES (?, ?)", 
        to_params(&row2).unwrap()
    )?;

    // 使用query()和from_rows()反序列化 - 最高效的方式
    let mut statement = connection.prepare("SELECT * FROM example")?;
    let mut res = from_rows::<Example>(statement.query([])?);
    
    // 获取第一行数据
    if let Some(row) = res.next() {
        println!("First row: {:?}", row?);
    }

    Ok(())
}

完整示例

use serde_derive::{Deserialize, Serialize};
use serde_rusqlite::*;
use rusqlite::{params, Connection};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct User {
    id: i32,
    name: String,
    email: String,
    active: bool,
}

fn main() -> rusqlite::Result<()> {
    // 创建数据库连接
    let conn = Connection::open_in_memory()?;
    
    // 创建用户表
    conn.execute(
        "CREATE TABLE users (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            email TEXT UNIQUE NOT NULL,
            active INTEGER
        )",
        [],
    )?;

    // 插入用户数据
    let new_user = User {
        id: 1,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
        active: true,
    };
    
    // 使用命名参数插入
    conn.execute(
        "INSERT INTO users (id, name, email, active) VALUES (:id, :name, :email, :active)",
        to_params_named(&new_user).unwrap().to_slice().as_slice(),
    )?;

    // 查询所有用户
    let mut stmt = conn.prepare("SELECT id, name, email, active FROM users")?;
    let user_iter = from_rows::<User>(stmt.query([])?);
    
    for user in user_iter {
        println!("Found user: {:?}", user?);
    }

    // 更新用户数据
    let updated_user = User {
        id: 1,
        name: "Alice Smith".to_string(),
        email: "alice.smith@example.com".to_string(),
        active: false,
    };
    
    conn.execute(
        "UPDATE users SET name = :name, email = :email, active = :active WHERE id = :id",
        to_params_named(&updated_user).unwrap().to_slice().as_slice(),
    )?;

    Ok(())
}

许可证

MIT OR Apache-2.0


1 回复

Rust数据库操作库serde_rusqlite的使用指南

serde_rusqlite是一个结合了SQLite数据库操作和Serde序列化的Rust库,它允许你在SQLite数据库和Rust数据结构之间进行高效的序列化和反序列化操作。

主要特性

  • 无缝集成SQLite和Serde
  • 支持自定义类型序列化
  • 提供便捷的查询和插入接口
  • 类型安全的数据库操作

基本使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
rusqlite = "0.29.0"
serde_rusqlite = "0.5.0"

定义可序列化的结构体

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct User {
    id: i32,
    name: String,
    email: String,
    age: Option<u32>,
}

基本数据库操作示例

use rusqlite::{Connection, params};
use serde_rusqlite::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建或打开数据库连接
    let conn = Connection::open_in_memory()?;
    
    // 创建表
    conn.execute(
        "CREATE TABLE users (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            email TEXT NOT NULL,
            age INTEGER
        )",
        [],
    )?;
    
    // 插入数据
    let user = User {
        id: 1,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
        age: Some(30),
    };
    
    conn.execute(
        "INSERT INTO users (id, name, email, age) VALUES (?1, ?2, ?3, ?4)",
        params![user.id, user.name, user.email, user.age],
    )?;
    
    // 查询数据 - 使用serde_rusqlite的便捷方法
    let mut stmt = conn.prepare("SELECT id, name, email, age FROM users")?;
    let users: Vec<User] = from_rows(stmt.query([])?).collect::<Result<_, _>>()?;
    
    println!("Users: {:?}", users);
    
    Ok(())
}

高级用法

使用to_params_named进行命名参数绑定

let user = User {
    id: 2,
    name: "Bob".to_string(),
    email: "bob@example.com".to_string(),
    age: None,
};

let named_params = to_params_named(&user).unwrap();
conn.execute(
    "INSERT INTO users (id, name, email, age) VALUES (:id, :name, :email, :age)",
    &named_params,
)?;

处理JSON字段

#[derive(Serialize, Deserialize, Debug)]
struct UserProfile {
    preferences: serde_json::Value,
    metadata: Option<serde_json::Value>,
}

// 创建支持JSON字段的表
conn.execute(
    "CREATE TABLE user_profiles (
        user_id INTEGER PRIMARY KEY,
        preferences TEXT NOT NULL,
        metadata TEXT
        )",
    [],
)?;

let profile = UserProfile {
    preferences: serde_json::json!({
        "theme": "dark",
        "notifications": true
    }),
    metadata: Some(serde_json::json!({
        "created_at": "2023-01-01",
        "source": "web"
    })),
};

// 插入JSON数据
conn.execute(
    "INSERT INTO user_profiles (user_id, preferences, metadata) VALUES (?1, ?2, ?3)",
    params![1, serde_json::to_string(&profile.preferences)?, 
            profile.metadata.as_ref().map(|m| serde_json::to_string(m)).transpose()?],
)?;

// 查询并反序列化JSON数据
let mut stmt = conn.prepare("SELECT preferences, metadata FROM user_profiles WHERE user_id = ?")?;
let row = stmt.query_row([1], |row| {
    let prefs: String = row.get(0)?;
    let meta: Option<String> = row.get(1)?;
    Ok((prefs, meta))
})?;

let (prefs_str, meta_str) = row;
let prefs: serde_json::Value = serde_json::from_str(&prefs_str)?;
let meta: Option<serde_json::Value> = meta_str.map(|s| serde_json::from_str(&s)).transpose()?;

println!("Preferences: {:?}", prefs);
println!("Metadata: {:?}", meta);

事务处理示例

fn create_user_with_profile(conn: &Connection, user: User, profile: UserProfile) -> Result<(), Box<dyn std::error::Error>> {
    let tx = conn.transaction()?;
    
    // 插入用户
    tx.execute(
        "INSERT INTO users (id, name, email, age) VALUES (?1, ?2, ?3, ?4)",
        params![user.id, user.name, user.email, user.age],
    )?;
    
    // 插入用户资料
    tx.execute(
        "INSERT INTO user_profiles (user_id, preferences, metadata) VALUES (?1, ?2, ?3)",
        params![
            user.id,
            serde_json::to_string(&profile.preferences)?,
            profile.metadata.as_ref().map(|m| serde_json::to_string(m)).transpose()?
        ],
    )?;
    
    tx.commit()?;
    Ok(())
}

性能提示

  1. 对于批量插入,考虑使用事务
  2. 预编译常用查询语句
  3. 对于大型JSON字段,考虑直接使用SQLite的JSON扩展功能

serde_rusqlite通过结合SQLite的高效存储和Serde的强大序列化能力,为Rust开发者提供了便捷的数据库操作体验。

完整示例代码

下面是一个完整的serde_rusqlite使用示例,包含了基本CRUD操作、事务处理和JSON字段处理:

use rusqlite::{Connection, params};
use serde::{Deserialize, Serialize};
use serde_rusqlite::*;
use serde_json::{json, Value};

#[derive(Serialize, Deserialize, Debug)]
struct User {
    id: i32,
    name: String,
    email: String,
    age: Option<u32>,
}

#[derive(Serialize, Deserialize, Debug)]
struct UserProfile {
    preferences: Value,
    metadata: Option<Value>,
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建内存数据库连接
    let conn = Connection::open_in_memory()?;
    
    // 创建用户表
    conn.execute(
        "CREATE TABLE users (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL,
            email TEXT NOT NULL,
            age INTEGER
        )",
        [],
    )?;
    
    // 创建用户资料表
    conn.execute(
        "CREATE TABLE user_profiles (
            user_id INTEGER PRIMARY KEY,
            preferences TEXT NOT NULL,
            metadata TEXT
        )",
        [],
    )?;

    // 示例1: 基本CRUD操作
    let user = User {
        id: 1,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
        age: Some(30),
    };

    // 插入用户
    conn.execute(
        "INSERT INTO users (id, name, email, age) VALUES (?1, ?2, ?3, ?4)",
        params![user.id, user.name, user.email, user.age],
    )?;

    // 查询用户
    let mut stmt = conn.prepare("SELECT id, name, email, age FROM users")?;
    let users: Vec<User> = from_rows(stmt.query([])?).collect::<Result<_, _>>()?;
    println!("All users: {:?}", users);

    // 示例2: 使用事务处理
    let new_user = User {
        id: 2,
        name: "Bob".to_string(),
        email: "bob@example.com".to_string(),
        age: None,
    };

    let profile = UserProfile {
        preferences: json!({
            "theme": "light",
            "notifications": false
        }),
        metadata: Some(json!({
            "created_at": "2023-01-02",
            "source": "mobile"
        })),
    };

    create_user_with_profile(&conn, new_user, profile)?;
    println!("User with profile created successfully");

    // 示例3: JSON字段查询
    let mut stmt = conn.prepare("SELECT preferences, metadata FROM user_profiles WHERE user_id = ?")?;
    let row = stmt.query_row([2], |row| {
        let prefs: String = row.get(0)?;
        let meta: Option<String> = row.get(1)?;
        Ok((prefs, meta))
    })?;

    let (prefs_str, meta_str) = row;
    let prefs: Value = serde_json::from_str(&prefs_str)?;
    let meta: Option<Value> = meta_str.map(|s| serde_json::from_str(&s)).transpose()?;

    println!("User preferences: {:?}", prefs);
    println!("User metadata: {:?}", meta);

    Ok(())
}

fn create_user_with_profile(conn: &Connection, user: User, profile: UserProfile) -> Result<(), Box<dyn std::error::Error>> {
    let tx = conn.transaction()?;
    
    // 插入用户
    tx.execute(
        "INSERT INTO users (id, name, email, age) VALUES (?1, ?2, ?3, ?4)",
        params![user.id, user.name, user.email, user.age],
    )?;
    
    // 插入用户资料
    tx.execute(
        "INSERT INTO user_profiles (user_id, preferences, metadata) VALUES (?1, ?2, ?3)",
        params![
            user.id,
            serde_json::to_string(&profile.preferences)?,
            profile.metadata.as_ref().map(|m| serde_json::to_string(m)).transpose()?
        ],
    )?;
    
    tx.commit()?;
    Ok(())
}

这个完整示例展示了:

  1. 如何定义可序列化的结构体
  2. 基本的数据库CRUD操作
  3. 使用事务确保数据一致性
  4. 处理JSON字段的序列化和反序列化
  5. 使用serde_rusqlite的便捷查询方法

代码中的注释详细解释了每个步骤的作用,帮助你理解如何使用serde_rusqlite进行高效的数据库操作。

回到顶部