【发布时间】:2021-05-13 03:10:54
【问题描述】:
在我的 JPA 模型中,我有学生、课程和出勤实体。出席代表学生和课程之间的连接表,并具有唯一约束以确保学生不能多次参加课程
@Entity
@Table(name = "attendance", uniqueConstraints = {
@UniqueConstraint(name = "u_attendance", columnNames = {
"student_id", "course_id"
})
})
public class Attendance {
// class body omitted
}
我有一个控制器端点,允许学生参加课程
@ResponseStatus(HttpStatus.OK)
@Transactional
public void attendCourse(@PathVariable UUID courseId) {
attendanceService.attend(courseId);
}
attendanceService.attend 方法会在保存新的出勤实体之前检查学生是否已经在参加此课程
public void accept(UUID courseId) {
Student currentStudent = studentService.getCurrent();
Course course = courseService.findById(courseId);
Optional<Attendance> isAttending = attendanceRepository
.findByCourseIdAndStudentId(courseId, currentStudent.getId();
if (isAttending.isPresent()) {
// student is already attending the course
return;
}
Attendance attendance = new Attendance();
attendance.setStudent(currentStudent);
attendance.setCourse(course);
attendanceRepository.save(attendance);
}
但是,有时在生产环境中尝试保存新的Attendance 会抛出DataIntegrityViolationException,表示尝试保存重复的Attendance。
鉴于此,我不确定为什么会发生这种情况
- 端点在读写事务中执行?
- 我在保存之前检查
Attendance是否已经存在?
我想为了防止这种情况,我需要更改事务语义,可能通过执行以下操作之一
- 更改隔离级别
- 在执行
accept方法之前获取考勤表的排他锁 - 使用嵌套事务
我意识到我可以通过进行以下更改来解决/忽略该问题
try {
attendanceRepository.save(attendance);
} catch (DataIntegrityViolationException ex) {
logger.warn("Attendance already exists", ex)
}
但如果可能的话,我更愿意防止抛出异常
【问题讨论】:
标签: java spring-boot hibernate jpa spring-transactions