You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为预订系统的重叠时间段设置乐观锁?

并发预订场景下的时间重叠拦截问题与乐观锁配置疑问

我正在开发一个场地预订系统,用户可预订特定场地的时间段。目前遇到的问题是并发场景下,时间重叠的两个预订会被同时存入数据库。

针对完全相同的时间段,我已经通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:46:02