# 数据库访问优化指南 ## 🚨 问题描述 在多线程环境中,数据库连接锁竞争是常见问题,表现为: - 程序卡在 `conn.lock().unwrap()` - 死锁导致程序无响应 - 性能下降 ## 🎯 优化方案 ### 1. 使用 Database 辅助方法(推荐) ```rust // ❌ 旧方式 - 容易造成锁竞争 pub fn get_photos(&self, model_id: &str) -> Result> { let conn = self.database.get_connection(); let conn = conn.lock().unwrap(); // 可能无限等待 // 长时间持有锁进行数据库操作 let mut stmt = conn.prepare("SELECT ...")?; // ... } // ✅ 新方式 - 使用 with_connection 辅助方法 pub fn get_photos(&self, model_id: &str) -> Result> { self.database.with_connection(|conn| { let mut stmt = conn.prepare("SELECT ...")?; // 数据库操作 Ok(photos) }) } ``` ### 2. Database 辅助方法实现 ```rust impl Database { /// 执行数据库操作的辅助方法,自动处理锁的获取和释放 pub fn with_connection(&self, operation: F) -> Result where F: FnOnce(&Connection) -> Result, { match self.connection.try_lock() { Ok(conn) => { // 成功获取锁,执行操作 operation(&*conn) }, Err(_) => { // 锁被占用,等待一小段时间后重试 std::thread::sleep(std::time::Duration::from_millis(10)); // 使用阻塞方式获取锁,但有错误处理 let conn = self.connection.lock().map_err(|e| { eprintln!("数据库连接锁获取失败: {}", e); rusqlite::Error::SqliteFailure( rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_BUSY), Some("数据库连接被锁定".to_string()), ) })?; operation(&*conn) } } } /// 执行只读查询 pub fn query(&self, operation: F) -> Result where F: FnOnce(&Connection) -> Result, { self.with_connection(operation) } /// 执行写入操作 pub fn execute(&self, operation: F) -> Result where F: FnOnce(&Connection) -> Result, { self.with_connection(operation) } } ``` ## 🔧 最佳实践 ### 1. 缩小锁的作用域 ```rust // ❌ 锁持有时间过长 pub fn bad_example(&self) -> Result<()> { let conn = self.database.get_connection(); let conn = conn.lock().unwrap(); // 大量计算和处理 let processed_data = expensive_computation(); // 数据库操作 conn.execute("INSERT ...", params)?; Ok(()) } // ✅ 最小化锁持有时间 pub fn good_example(&self) -> Result<()> { // 在锁外进行计算 let processed_data = expensive_computation(); // 只在需要时持有锁 self.database.execute(|conn| { conn.execute("INSERT ...", params)?; Ok(()) }) } ``` ### 2. 避免嵌套锁 ```rust // ❌ 可能导致死锁 pub fn bad_nested_locks(&self) -> Result<()> { let conn1 = self.database.get_connection(); let _guard1 = conn1.lock().unwrap(); // 在持有锁时调用其他可能需要锁的方法 self.other_method_that_needs_lock()?; Ok(()) } // ✅ 避免嵌套锁 pub fn good_no_nested_locks(&self) -> Result<()> { // 分别处理,避免嵌套 let data = self.prepare_data()?; self.database.execute(|conn| { // 只在这里持有锁 conn.execute("INSERT ...", params)?; Ok(()) }) } ``` ### 3. 使用事务优化批量操作 ```rust // ✅ 批量操作使用事务 pub fn batch_insert(&self, items: &[Item]) -> Result<()> { self.database.execute(|conn| { let tx = conn.transaction()?; for item in items { tx.execute("INSERT ...", params)?; } tx.commit()?; Ok(()) }) } ``` ### 4. 错误处理和超时 ```rust // ✅ 带超时的锁获取 pub fn with_timeout(&self) -> Result<()> { use std::time::{Duration, Instant}; let start = Instant::now(); let timeout = Duration::from_secs(5); loop { match self.database.connection.try_lock() { Ok(conn) => { // 成功获取锁 return self.do_operation(&*conn); }, Err(_) if start.elapsed() < timeout => { // 继续重试 std::thread::sleep(Duration::from_millis(10)); continue; }, Err(_) => { // 超时 return Err(rusqlite::Error::SqliteFailure( rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_BUSY), Some("数据库操作超时".to_string()), )); } } } } ``` ## 📊 性能监控 ```rust // 添加性能监控 pub fn monitored_operation(&self) -> Result<()> { let start = std::time::Instant::now(); let result = self.database.with_connection(|conn| { // 数据库操作 Ok(()) }); let duration = start.elapsed(); if duration > std::time::Duration::from_millis(100) { eprintln!("慢查询警告: 操作耗时 {:?}", duration); } result } ``` ## 🎯 总结 1. **使用 `with_connection` 方法**:自动处理锁的获取和释放 2. **最小化锁持有时间**:只在必要时持有锁 3. **避免嵌套锁**:防止死锁 4. **使用 `try_lock`**:避免无限等待 5. **添加错误处理**:优雅处理锁竞争 6. **使用事务**:优化批量操作 7. **性能监控**:识别慢查询 这些优化可以显著提高数据库访问的性能和稳定性,避免锁竞争问题。