java - 处理餐厅场景中的同时预订请求

标签 java spring multithreading hibernate jpa

我正在为餐厅预订系统开发一个 REST API 项目,该项目使用 Spring boot 和 HSQLDB,使用 Spring data JPA。该场景是用户可以调用预订服务来预订特定时间的餐 table 。在给定时间段内只能允许一次预订。

我的问题是如何处理 2 个或更多不同用户同时调用 REST API 以同时预订同一张 table 的情况。

我对此进行了搜索,发现乐观锁定可以用于此目的,但我不确定它在这种情况下有何帮助,除非我对餐厅表记录进行任何更新。

下面是我的项目结构。

预订 DAO

@Entity
public class Booking {

    @Id
    @GeneratedValue
    private Long id;
    private String bookingId;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
    private LocalDateTime bookingStart;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
    private LocalDateTime bookingEnd;
    @OneToOne
    private RestaurantTable table;
    private String customerName;

    ..Setter/Getter
}

餐厅 DAO

@Entity
public class RestaurantTable {

    @Id
    @GeneratedValue
    private Long id;
    private Integer tableId;
    private Integer capacity;
    private String description;

    //Setter/Getter
}

预订创建服务。

@Service
public class BookingService{

    @Transactional
    public Booking addBooking(final BookingDTO bookingRequest) {
        LOG.debug("Creating new booking for request: {}", bookingRequest);
        validateBookingData(bookingRequest);
        return bookingCreateService.createBooking(bookingRequest);
    }
}

@Service
public class BookingCreateService {

    @Autowired
    private BookingRepository bookingRepository;
    @Autowired
    private TableRepository tableRepository;

    public Booking createBooking(final BookingDTO bookingRequest) {
        Booking booking = null;
        final LocalDateTime bookingStart = bookingRequest.getBookingTime();
        final LocalDateTime bookingEnd = bookingRequest.getBookingTime().plusHours(1);
        RestaurantTable table = tableRepository
                .findAvailableTableWithAdequateSeatingCapacity(bookingStart, bookingEnd, bookingRequest.getCustomers())
                .stream().findFirst().orElse(null);

        if (table != null) {
            booking = saveBooking(table, bookingStart, bookingEnd, bookingRequest.getCustomerName());
        } else {
            throwErrorWithRecomemdedTime(bookingRequest.getCustomers(), bookingStart);
        }
        return booking;
    }

    private Booking saveBooking(final RestaurantTable table, final LocalDateTime bookingStart,
            final LocalDateTime bookingEnd, final String customerName) {
        Booking booking = new Booking();
        booking.setBookingStart(bookingStart);
        booking.setBookingEnd(bookingEnd);
        booking.setTable(table);
        booking.setBookingId(RandomStringUtils.randomAlphanumeric(7));
        booking.setCustomerName(customerName);
        return bookingRepository.save(booking);
    }

    private void throwErrorWithRecomemdedTime(final Integer customerCount, final LocalDateTime bookingStart) {
        Booking closestBookingWithFreeSlot = bookingRepository.findClosestBookingToInputTime(bookingStart);
        StringBuilder errorMsg = new StringBuilder();
        errorMsg.append("Table not available for capacity: ").append(customerCount).append(".");
        if (closestBookingWithFreeSlot != null) {
            errorMsg.append(" Table available after " + closestBookingWithFreeSlot.getBookingEnd() + ".");
        }
        throw new DataValidationException(errorMsg.toString());
    }
}

如果我使用 Thread.sleep 保持 BookingService 的完成状态,并创建另一个预订同一张 table 的请求,那么它将在同一时间为同一张 table 创建两个预订。我怎样才能避免这种情况?我应该同步它吗?同步会导致性能问题吗?

最佳答案

如果您在数据库表上添加唯一约束(包括日期、表和时间段),只要您使用事务,您就应该在两者之一上收到错误。 您可以捕获错误并向客户端返回一条消息,表明时间不再可用。

关于java - 处理餐厅场景中的同时预订请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47428790/

相关文章:

java - 处理 JAR 和开发中的资源文件路径

java - hashmap中的entrySet是如何创建和修改的?

java - 从链表中剪切一部分?

java - 如何在类型为接口(interface)的注入(inject)点中注入(inject)实现

java:如何设置全局线程ID?

java - 警告| Java 发现了可能表明安全问题的应用程序内容

spring - 将 Spring Data Rest 存储库注入(inject)实用程序类

java - JSP - 获取类枚举类型属性时出错

c - 服务器中的 Leader/Follower pthread 实现

multithreading - Rust多线程异步Websocket服务器