【问题标题】:How can I prevent this DataIntegrityViolationException when saving a new entity?保存新实体时如何防止出现此 DataIntegrityViolationException?
【发布时间】: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


    【解决方案1】:

    如果同时多次调用端点,就会发生这种情况

    1. 捕捉DataIntegrityViolationException
    2. attendanceRepository.findByCourseIdAndStudentId()
    3. 如果Attendance 存在返回错误:已经拥有它
    4. 如果不存在,则返回内部服务器错误
    5. 在任何情况下都创建日志消息

    由您决定是否保留第一个电话attendanceRepository.findByCourseIdAndStudentId()

    使用 JMeter 测试并行请求。

    【讨论】:

      猜你喜欢
      • 2018-09-12
      • 1970-01-01
      • 2021-06-16
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      • 1970-01-01
      相关资源
      最近更新 更多