diff --git a/client-api/src/main/java/org/jiayunet/service/UserProfileService.java b/client-api/src/main/java/org/jiayunet/service/UserProfileService.java index 06ed1b0..434629c 100644 --- a/client-api/src/main/java/org/jiayunet/service/UserProfileService.java +++ b/client-api/src/main/java/org/jiayunet/service/UserProfileService.java @@ -10,6 +10,8 @@ import org.jiayunet.tool.UserSecurityTool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import java.time.Instant; import java.util.List; @@ -369,12 +371,41 @@ public class UserProfileService { // ==================== 从简历同步到个人资料 ==================== /** - * 根据简历ID同步更新个人资料 + * 根据简历ID同步更新个人资料(AI分析同步执行,阻塞至分析完成) *
1. 校验简历归属 2. 读取简历主表+6子表 3. 事务内覆盖写入Profile主表+6子表 4. 同步执行一次AI分析
+ *适用于前端需要拿到分析结果的场景(如简历上传解析后立即展示)
*/ @Transactional(rollbackFor = Exception.class) public void syncProfileFromResume(Long resumeId) { Long userId = UserSecurityTool.getUserId(); + copyResumeToProfile(userId, resumeId); + // 事务内所有数据写入完成,同步执行AI分析并等待完成 + userProfileAnalyzeService.analyzeUserProfileSync(userId); + } + + /** + * 根据简历ID同步更新个人资料(AI分析异步执行,立即返回) + *1. 校验简历归属 2. 读取简历主表+6子表 3. 事务内覆盖写入Profile主表+6子表 4. 事务提交后异步触发AI分析
+ *适用于同步只是副作用、不需要等待分析结果的场景(如设置默认简历)
+ */ + @Transactional(rollbackFor = Exception.class) + public void syncProfileFromResumeAsync(Long resumeId) { + Long userId = UserSecurityTool.getUserId(); + copyResumeToProfile(userId, resumeId); + // AI分析必须等事务提交后再触发,否则异步线程读不到本次写入的数据 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + userProfileAnalyzeService.analyzeUserProfile(userId); + } + }); + } + + /** + * 将简历数据覆盖写入个人资料(主表+6子表),不触发AI分析 + *由 syncProfileFromResume / syncProfileFromResumeAsync 复用,须在事务内调用
+ */ + private void copyResumeToProfile(Long userId, Long resumeId) { // 1. 校验简历归属当前用户 UserResume resume = userResumeMapper.selectById(resumeId); @@ -557,9 +588,6 @@ public class UserProfileService { }).collect(Collectors.toList()); organizationMapper.batchInsert(profileOrganizationList); } - - // 10. 事务内所有数据写入完成,同步执行AI分析并等待完成 - userProfileAnalyzeService.analyzeUserProfileSync(userId); } // ==================== 从个人资料生成简历 ==================== diff --git a/client-api/src/main/java/org/jiayunet/service/UserResumeService.java b/client-api/src/main/java/org/jiayunet/service/UserResumeService.java index 4f31d6c..35985a9 100644 --- a/client-api/src/main/java/org/jiayunet/service/UserResumeService.java +++ b/client-api/src/main/java/org/jiayunet/service/UserResumeService.java @@ -38,6 +38,9 @@ public class UserResumeService { @Autowired private MemberUserMapper memberUserMapper; + @Autowired + private UserProfileService userProfileService; + @Value("${app.resume.max-count:5}") private int maxResumeCount; @@ -142,6 +145,10 @@ public class UserResumeService { .set(UserResume::getHobbies, resume.getHobbies()) .set(UserResume::getLanguageSkills, resume.getLanguageSkills()) .set(UserResume::getUpdateTime, now)); + // 默认简历即用户主简历,内容变更后同步覆盖个人资料;AI提取异步执行,不阻塞本次请求 + if (Integer.valueOf(1).equals(existing.getIsDefault())) { + userProfileService.syncProfileFromResumeAsync(resumeId); + } return resumeId; } @@ -742,7 +749,8 @@ public class UserResumeService { /** * 设置默认简历 - *1. 查询用户所有简历,无简历则报错 2. 校验resumeId存在于用户简历中 3. 全部置为非默认,目标简历置为默认
+ *1. 查询用户所有简历,无简历则报错 2. 校验resumeId存在于用户简历中 3. 全部置为非默认,目标简历置为默认 + * 4. 将该简历同步到个人资料,AI提取在事务提交后异步执行
*/ @Transactional(rollbackFor = Exception.class) public void setDefaultResume(Long resumeId) { @@ -759,6 +767,8 @@ public class UserResumeService { userResumeMapper.update(null, new LambdaUpdateWrapper