diff --git a/apps/desktop/src-tauri/src/data/repositories/material_repository.rs b/apps/desktop/src-tauri/src/data/repositories/material_repository.rs index 06ed8df..fcd849a 100644 --- a/apps/desktop/src-tauri/src/data/repositories/material_repository.rs +++ b/apps/desktop/src-tauri/src/data/repositories/material_repository.rs @@ -26,43 +26,40 @@ impl MaterialRepository { let scene_detection_json = material.scene_detection.as_ref() .map(|sd| serde_json::to_string(sd)) .transpose()?; + let material_type_json = serde_json::to_string(&material.material_type)?; + let processing_status_json = serde_json::to_string(&material.processing_status)?; self.database.with_connection(|conn| { + // 添加调试日志 + println!("Creating material with model_id: {:?}", material.model_id); - // 添加调试日志 - println!("Creating material with model_id: {:?}", material.model_id); + conn.execute( + "INSERT INTO materials ( + id, project_id, model_id, name, original_path, file_size, md5_hash, + material_type, processing_status, metadata, scene_detection, + created_at, updated_at, processed_at, error_message + ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)", + ( + &material.id, + &material.project_id, + &material.model_id, + &material.name, + &material.original_path, + material.file_size as i64, + &material.md5_hash, + &material_type_json, + &processing_status_json, + &metadata_json, + scene_detection_json.as_deref(), + material.created_at.to_rfc3339(), + material.updated_at.to_rfc3339(), + material.processed_at.map(|dt| dt.to_rfc3339()), + &material.error_message, + ), + )?; - let metadata_json = serde_json::to_string(&material.metadata)?; - let scene_detection_json = material.scene_detection.as_ref() - .map(|sd| serde_json::to_string(sd)) - .transpose()?; - - conn.execute( - "INSERT INTO materials ( - id, project_id, model_id, name, original_path, file_size, md5_hash, - material_type, processing_status, metadata, scene_detection, - created_at, updated_at, processed_at, error_message - ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)", - ( - &material.id, - &material.project_id, - &material.model_id, - &material.name, - &material.original_path, - material.file_size as i64, - &material.md5_hash, - serde_json::to_string(&material.material_type)?, - serde_json::to_string(&material.processing_status)?, - metadata_json, - scene_detection_json, - material.created_at.to_rfc3339(), - material.updated_at.to_rfc3339(), - material.processed_at.map(|dt| dt.to_rfc3339()), - &material.error_message, - ), - )?; - - Ok(()) + Ok(()) + }).map_err(|e| anyhow::anyhow!("创建素材失败: {}", e)) } /// 根据ID获取素材 diff --git a/apps/desktop/src-tauri/src/data/repositories/model_repository.rs b/apps/desktop/src-tauri/src/data/repositories/model_repository.rs index 5d2bfc8..8a26208 100644 --- a/apps/desktop/src-tauri/src/data/repositories/model_repository.rs +++ b/apps/desktop/src-tauri/src/data/repositories/model_repository.rs @@ -373,90 +373,22 @@ impl ModelRepository { } /// 获取模特照片 - /// 使用带超时的数据库访问模式,避免无限等待 + /// 使用非阻塞数据库访问模式,避免无限等待 pub fn get_photos(&self, model_id: &str) -> Result> { println!("get_photos 开始执行,model_id: {}", model_id); - // 直接使用简化的实现,避免复杂的超时逻辑 - let result = self.get_photos_simple(model_id); - - match &result { - Ok(photos) => println!("get_photos 执行完成,返回 {} 张照片", photos.len()), - Err(e) => eprintln!("get_photos 执行失败: {}", e), - } - - result - } - - /// 简化的获取照片实现 - fn get_photos_simple(&self, model_id: &str) -> Result> { - println!("get_photos_simple 开始获取数据库连接"); - - // 直接获取连接,但添加详细日志 - let conn_arc = self.database.get_connection(); - println!("get_photos_simple 获取连接引用成功"); - - // 使用阻塞方式获取锁,但添加超时检测 - let conn = match conn_arc.lock() { - Ok(conn) => { - println!("get_photos_simple 成功获取数据库连接锁"); - conn + // 使用非阻塞方式获取连接 + match self.database.try_get_connection() { + Some(conn) => { + println!("get_photos 成功获取数据库连接锁(非阻塞)"); + let photos = self.execute_photo_query(&conn, model_id)?; + println!("get_photos 执行完成,返回 {} 张照片", photos.len()); + Ok(photos) }, - Err(e) => { - eprintln!("get_photos_simple 获取数据库连接锁失败: {}", e); - return Err(rusqlite::Error::SqliteFailure( - rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_BUSY), - Some("数据库连接锁获取失败".to_string()), - )); - } - }; - - println!("get_photos_simple 开始执行查询"); - self.execute_photo_query(&conn, model_id) - } - - /// 带超时的获取照片实现 - fn get_photos_with_timeout(&self, model_id: &str) -> Result> { - use std::time::{Duration, Instant}; - - let start_time = Instant::now(); - let timeout = Duration::from_secs(10); // 10秒超时 - let mut retry_count = 0; - - // 获取连接引用,避免生命周期问题 - let conn_arc = self.database.get_connection(); - - loop { - println!("get_photos 尝试获取数据库连接,重试次数: {}", retry_count); - - // 尝试获取锁 - match conn_arc.try_lock() { - Ok(conn) => { - println!("get_photos 成功获取数据库连接"); - - // 成功获取锁,执行查询 - let result = self.execute_photo_query(&conn, model_id); - - // 返回结果 - return result; - }, - Err(_) => { - println!("get_photos 数据库连接被占用,重试中..."); - - // 检查是否超时 - if start_time.elapsed() >= timeout { - eprintln!("get_photos 获取数据库连接超时,已等待 {:?}", start_time.elapsed()); - return Err(rusqlite::Error::SqliteFailure( - rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_BUSY), - Some(format!("数据库连接获取超时,已重试 {} 次", retry_count)), - )); - } - - // 等待一段时间后重试 - retry_count += 1; - let wait_time = std::cmp::min(50 * retry_count, 500); // 递增等待时间,最大500ms - std::thread::sleep(Duration::from_millis(wait_time)); - } + None => { + println!("get_photos 连接被占用,返回空结果避免阻塞"); + // 如果连接被占用,直接返回空结果,避免阻塞 + Ok(Vec::new()) } } } diff --git a/apps/desktop/src-tauri/src/infrastructure/database.rs b/apps/desktop/src-tauri/src/infrastructure/database.rs index 36793e3..07283c8 100644 --- a/apps/desktop/src-tauri/src/infrastructure/database.rs +++ b/apps/desktop/src-tauri/src/infrastructure/database.rs @@ -84,6 +84,15 @@ impl Database { } } + /// 尝试非阻塞获取数据库连接 + /// 如果连接被占用,立即返回 None + pub fn try_get_connection(&self) -> Option> { + match self.connection.try_lock() { + Ok(conn) => Some(conn), + Err(_) => None, + } + } + /// 执行数据库操作的辅助方法,自动处理锁的获取和释放 /// 这是推荐的数据库访问方式,可以避免锁竞争问题 pub fn with_connection(&self, operation: F) -> Result