65 lines
1.8 KiB
Rust
65 lines
1.8 KiB
Rust
//! SQLite 数据库连接管理
|
|
|
|
use std::path::Path;
|
|
use std::sync::Arc;
|
|
|
|
use anyhow::Result;
|
|
use rusqlite::Connection;
|
|
use tokio::sync::Mutex;
|
|
|
|
use crate::migrations;
|
|
|
|
/// SQLite 数据库管理器
|
|
pub struct Database {
|
|
/// 数据库连接(线程安全)
|
|
conn: Arc<Mutex<Connection>>,
|
|
}
|
|
|
|
impl Database {
|
|
/// 打开(或创建)数据库文件
|
|
pub async fn open(path: &Path) -> Result<Self> {
|
|
let conn = Connection::open(path)?;
|
|
// GUI 与 MCP server 多进程写同库(WAL 下写写仍互斥),无 busy_timeout 时并发写
|
|
// 立即报 SQLITE_BUSY。设 5s 等待,让短暂持锁的一方先完成而非直接失败。
|
|
conn.busy_timeout(std::time::Duration::from_millis(5000))?;
|
|
conn.execute_batch("PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;")?;
|
|
|
|
// 执行迁移
|
|
let db = Self {
|
|
conn: Arc::new(Mutex::new(conn)),
|
|
};
|
|
db.run_migrations().await?;
|
|
|
|
tracing::info!("数据库已打开: {}", path.display());
|
|
Ok(db)
|
|
}
|
|
|
|
/// 打开内存数据库(用于测试)
|
|
pub async fn open_in_memory() -> Result<Self> {
|
|
let conn = Connection::open_in_memory()?;
|
|
conn.execute_batch("PRAGMA foreign_keys=ON;")?;
|
|
|
|
let db = Self {
|
|
conn: Arc::new(Mutex::new(conn)),
|
|
};
|
|
db.run_migrations().await?;
|
|
|
|
Ok(db)
|
|
}
|
|
|
|
/// 执行数据库迁移
|
|
async fn run_migrations(&self) -> Result<()> {
|
|
let conn = self.conn.lock().await;
|
|
migrations::run(&conn)?;
|
|
tracing::info!("数据库迁移完成");
|
|
Ok(())
|
|
}
|
|
|
|
/// 获取连接的锁守卫
|
|
///
|
|
/// TODO: 考虑使用 r2d2 连接池替代单连接 Mutex
|
|
pub fn conn(&self) -> Arc<Mutex<Connection>> {
|
|
Arc::clone(&self.conn)
|
|
}
|
|
}
|