Spring Boot更新方法调用删增报唯一键重复错误求助
解决Spring事务内删除后新增触发唯一键冲突问题
问题根源
你遇到的问题核心是Spring动态代理的机制限制:在同一个类内部调用带有@Transactional注解的方法时,Spring不会创建代理对象来拦截方法调用,所以deleteById和addSemester上的Propagation.REQUIRES_NEW属性完全没生效。整个updateSemesterById的操作处于同一个事务中,删除操作的修改还没提交到数据库,新增操作就执行了,此时数据库里旧的学期记录依然存在,触发唯一键约束冲突。
解决方案
方案1:拆分事务方法到独立Service类
把需要独立事务的方法抽离到另一个Service类中,通过依赖注入调用,这样Spring会为这个独立Service生成代理,确保REQUIRES_NEW事务生效。
步骤1:创建独立的事务处理Service
@Service public class SemesterTransactionHandler { private final SemesterRepository semesterRepository; // 构造注入(推荐) public SemesterTransactionHandler(SemesterRepository semesterRepository) { this.semesterRepository = semesterRepository; } @Transactional(propagation = Propagation.REQUIRES_NEW) public void addSemester(Long semesterId, LocalDate startDate, LocalDate endDate) { // 注意:原代码中semesterList是空集合,需构造实际的Semester对象 Set<Semester> semesterList = new HashSet<>(); semesterList.add(new Semester(semesterId, startDate, endDate)); // 根据实际实体类调整构造参数 semesterRepository.saveAll(semesterList); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void deleteById(Long semesterId) { semesterRepository.deleteBySemesterId(semesterId); } }
步骤2:在原Service中注入并调用
@Service public class SemesterService { private final SemesterTransactionHandler transactionHandler; public SemesterService(SemesterTransactionHandler transactionHandler) { this.transactionHandler = transactionHandler; } public void updateSemesterById(Long semesterId, LocalDate startDate, LocalDate endDate) { transactionHandler.deleteById(semesterId); transactionHandler.addSemester(semesterId, startDate, endDate); } }
方案2:使用AopContext获取代理对象
通过AopContext获取当前类的代理对象,调用自身的事务方法,强制触发代理拦截。
步骤1:开启代理暴露
在Spring配置类中添加exposeProxy = true:
@EnableAspectJAutoProxy(exposeProxy = true) @Configuration public class AppConfig { // 其他配置内容 }
步骤2:修改updateSemesterById方法
@Service public class SemesterService { private final SemesterRepository semesterRepository; public SemesterService(SemesterRepository semesterRepository) { this.semesterRepository = semesterRepository; } @Transactional(propagation = Propagation.REQUIRES_NEW) public void addSemester(Long semesterId, LocalDate startDate, LocalDate endDate) { Set<Semester> semesterList = new HashSet<>(); semesterList.add(new Semester(semesterId, startDate, endDate)); semesterRepository.saveAll(semesterList); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void deleteById(Long semesterId) { semesterRepository.deleteBySemesterId(semesterId); } public void updateSemesterById(Long semesterId, LocalDate startDate, LocalDate endDate) { // 通过代理对象调用事务方法 SemesterService proxy = (SemesterService) AopContext.currentProxy(); proxy.deleteById(semesterId); proxy.addSemester(semesterId, startDate, endDate); } }
额外注意点
原代码中addSemester方法的semesterList是空集合,这会导致新增操作没有实际数据写入数据库,需要根据业务逻辑构造正确的Semester对象添加到集合中。
内容的提问来源于stack exchange,提问作者vunhatchuong
相关产品推荐
相关产品推荐

