如何为预订系统的重叠时间段设置乐观锁?
并发预订场景下的时间重叠拦截问题与乐观锁配置疑问
我正在开发一个场地预订系统,用户可预订特定场地的时间段。目前遇到的问题是并发场景下,时间重叠的两个预订会被同时存入数据库。
针对完全相同的时间段,我已经通过Liquibase添加了唯一约束来拦截:
<addUniqueConstraint tableName="booking" constraintName="unique_location_booking" columnNames="location_id, start_time, end_time"/>
但这个约束只能阻止完全重复的预订,对于时间部分重叠的并发预订无效。比如以下两个请求:
{ "userId": 8, "startTime": "2024-07-04T12:00:00", "endTime": "2024-07-04T14:00:00", "location": { "id": 2 } }, { "userId": 9, "startTime": "2024-07-04T13:00:00", "endTime": "2024-07-04T15:00:00", "location": { "id": 2 } }
这类重叠的预订依然会被存入数据库。
我当前的前置检查逻辑如下:
@Transactional public BookingDTO createBooking(Booking booking) { Location location = locationRepository.findById(booking.getLocation().getId()) .orElseThrow(() -> new IllegalArgumentException("Location not found")); boolean bookingEndsBeforeItStarts = booking.getEndTime().isBefore(booking.getStartTime()); if (bookingEndsBeforeItStarts) throw new IllegalArgumentException("Booking can't end before it starts."); if (bookingRepository.existsOverlappingBooking(location.getId(), booking.getStartTime())) { throw new IllegalArgumentException("Overlapping booking exists for the given location and time."); } try { booking.setLocation(location); Booking savedBooking = bookingRepository.save(booking); return BookingMapper.toDTO(savedBooking); } catch (OptimisticLockException ex) { throw new IllegalStateException("Optimistic locking failure occurred", ex); } }
但并发场景下,因为预订数据还没入库,前置检查会同时放行重叠的请求。
我尝试在Repository中添加乐观锁配置:
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT) Booking save(Booking booking);
同时在Booking实体中添加了@Version字段,但是数据库中的version值始终为0,问题依然没解决。我的Booking实体定义如下:
@Entity @Table(name = "booking") @Data @NoArgsConstructor @AllArgsConstructor public class Booking { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "user_id", nullable = false) private Long userId; @ManyToOne @JoinColumn(name = "location_id", nullable = false) private Location location; @Column(name = "start_time", nullable = false) private LocalDateTime startTime; @Column(name = "end_time", nullable = false) private LocalDateTime endTime; @Version @Column(nullable = false) private Long version; }
请问如何正确配置乐观锁来解决这个并发下的时间重叠预订问题?
内容的提问来源于stack exchange,提问作者user26020733
相关产品推荐
相关产品推荐

