fix: 修复模特管理功能的数据库死锁问题
- 修复删除操作死锁:移除不必要的存在性检查 - 修复更新操作死锁:创建get_basic_by_id方法避免嵌套锁 - 优化get_all方法:分步执行避免嵌套数据库连接 - 添加详细的调试日志便于问题排查 - 确保前端在操作成功后正确刷新列表 解决的问题: - 删除模特时卡住不响应 - 编辑模特时卡住不响应 - 数据库连接嵌套锁导致的死锁 技术改进: - 分离基本信息查询和照片加载逻辑 - 优化数据库连接管理 - 增强错误处理和日志记录
This commit is contained in:
parent
5cf1f8bfca
commit
7a2d045be3
|
|
@ -104,8 +104,8 @@ impl ModelService {
|
|||
id: &str,
|
||||
request: UpdateModelRequest,
|
||||
) -> Result<Model> {
|
||||
// 获取现有模特
|
||||
let mut model = repository.get_by_id(id)?
|
||||
// 获取现有模特基本信息(避免死锁)
|
||||
let mut model = repository.get_basic_by_id(id)?
|
||||
.ok_or_else(|| anyhow!("模特不存在: {}", id))?;
|
||||
|
||||
// 更新字段
|
||||
|
|
@ -167,6 +167,10 @@ impl ModelService {
|
|||
repository.update(&model)
|
||||
.map_err(|e| anyhow!("更新模特失败: {}", e))?;
|
||||
|
||||
// 不加载照片信息,避免死锁
|
||||
// 前端会在更新成功后重新刷新列表
|
||||
model.photos = Vec::new();
|
||||
|
||||
Ok(model)
|
||||
}
|
||||
|
||||
|
|
@ -175,14 +179,18 @@ impl ModelService {
|
|||
repository: &ModelRepository,
|
||||
id: &str,
|
||||
) -> Result<()> {
|
||||
// 检查模特是否存在
|
||||
let _model = repository.get_by_id(id)?
|
||||
.ok_or_else(|| anyhow!("模特不存在: {}", id))?;
|
||||
println!("ModelService::delete_model 开始执行,ID: {}", id);
|
||||
|
||||
// 软删除模特
|
||||
// 直接执行删除操作,不需要先检查是否存在
|
||||
// 如果模特不存在,UPDATE 语句会返回 0 行受影响,这是正常的
|
||||
println!("执行软删除操作...");
|
||||
repository.delete(id)
|
||||
.map_err(|e| anyhow!("删除模特失败: {}", e))?;
|
||||
.map_err(|e| {
|
||||
println!("repository.delete 失败: {}", e);
|
||||
anyhow!("删除模特失败: {}", e)
|
||||
})?;
|
||||
|
||||
println!("ModelService::delete_model 执行成功");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl ModelRepository {
|
|||
/// 根据ID获取模特
|
||||
pub fn get_by_id(&self, id: &str) -> Result<Option<Model>> {
|
||||
let conn = self.connection.lock().unwrap();
|
||||
|
||||
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, name, stage_name, gender, age, height, weight, measurements,
|
||||
description, tags, avatar_path, contact_info, social_media,
|
||||
|
|
@ -96,6 +96,31 @@ impl ModelRepository {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
/// 根据ID获取模特基本信息(不加载照片,避免死锁)
|
||||
pub fn get_basic_by_id(&self, id: &str) -> Result<Option<Model>> {
|
||||
let conn = self.connection.lock().unwrap();
|
||||
|
||||
let mut stmt = conn.prepare(
|
||||
"SELECT id, name, stage_name, gender, age, height, weight, measurements,
|
||||
description, tags, avatar_path, contact_info, social_media,
|
||||
status, rating, created_at, updated_at, is_active
|
||||
FROM models WHERE id = ?1"
|
||||
)?;
|
||||
|
||||
let model_iter = stmt.query_map([id], |row| {
|
||||
self.row_to_model(row)
|
||||
})?;
|
||||
|
||||
for model in model_iter {
|
||||
let mut model = model?;
|
||||
// 不加载照片信息,避免死锁
|
||||
model.photos = Vec::new();
|
||||
return Ok(Some(model));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// 获取所有模特
|
||||
pub fn get_all(&self) -> Result<Vec<Model>> {
|
||||
println!("ModelRepository::get_all 开始执行");
|
||||
|
|
@ -304,13 +329,24 @@ impl ModelRepository {
|
|||
|
||||
/// 删除模特(软删除)
|
||||
pub fn delete(&self, id: &str) -> Result<()> {
|
||||
println!("ModelRepository::delete 开始执行,ID: {}", id);
|
||||
|
||||
let conn = self.connection.lock().unwrap();
|
||||
|
||||
conn.execute(
|
||||
println!("获取数据库连接成功");
|
||||
|
||||
let rows_affected = conn.execute(
|
||||
"UPDATE models SET is_active = 0, updated_at = ?1 WHERE id = ?2",
|
||||
(Utc::now().to_rfc3339(), id),
|
||||
)?;
|
||||
|
||||
println!("SQL执行成功,影响行数: {}", rows_affected);
|
||||
|
||||
if rows_affected == 0 {
|
||||
println!("警告: 没有找到要删除的模特记录,可能已经被删除");
|
||||
} else {
|
||||
println!("模特删除成功");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,14 +108,32 @@ pub async fn delete_model(
|
|||
state: State<'_, AppState>,
|
||||
id: String,
|
||||
) -> Result<(), String> {
|
||||
let repository_guard = state.get_model_repository()
|
||||
.map_err(|e| format!("获取模特仓库失败: {}", e))?;
|
||||
|
||||
let repository = repository_guard.as_ref()
|
||||
.ok_or("模特仓库未初始化")?;
|
||||
println!("开始删除模特,ID: {}", id);
|
||||
|
||||
ModelService::delete_model(repository, &id)
|
||||
.map_err(|e| e.to_string())
|
||||
let repository_guard = state.get_model_repository()
|
||||
.map_err(|e| {
|
||||
println!("获取模特仓库失败: {}", e);
|
||||
format!("获取模特仓库失败: {}", e)
|
||||
})?;
|
||||
|
||||
let repository = repository_guard.as_ref()
|
||||
.ok_or_else(|| {
|
||||
println!("模特仓库未初始化");
|
||||
"模特仓库未初始化".to_string()
|
||||
})?;
|
||||
|
||||
println!("调用 ModelService::delete_model");
|
||||
let result = ModelService::delete_model(repository, &id)
|
||||
.map_err(|e| {
|
||||
println!("删除模特失败: {}", e);
|
||||
e.to_string()
|
||||
});
|
||||
|
||||
if result.is_ok() {
|
||||
println!("模特删除成功");
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// 永久删除模特命令
|
||||
|
|
|
|||
Loading…
Reference in New Issue