【发布时间】:2021-11-19 07:07:20
【问题描述】:
我正在开发酒店和预订微服务,用户可以在其中为特定酒店预订特定入住和退房日期的房间。酒店可以包含许多相同类型的房间。 (我使用的是 spring-boot、spring-data-jpa 和 oracle 数据库)
当多个用户预订同一个酒店房间时,我想处理并发问题(考虑到房间有限,并非所有用户都能成功预订)。
我不会存储有关该房型在特定入住和退房日期有多少房间可用的任何信息,因为这样做会使检查房间的可用性变得复杂。因此,我没有任何可以添加 @Version 注释并使用乐观锁的实体。所以我采取的方法是,在预订被保存在数据库中之前,我会检查我的服务方法,如果那个房间在那个入住和退房日期是可用的。
我实现该服务方法(如下所示)的方式是获取该房间的所有即将到来的预订,这些预订与新用户(想要预订该房间)给出的入住和退房日期相冲突。如果房间可用,则预订将持续存在,否则将为用户抛出异常。下面是服务代码(变量名应该是不言自明的):
@Transactional
public Booking findRoomsAvailibilityAndSave(Booking bookingInfoFromUser) {
Booking persistedBooking = null;
boolean isAllRoomsAvailable = true;
int hotelId = bookingInfoFromUser.getHotelId();
LocalDate checkInDate = bookingInfoFromUser.getCheckInDate();
LocalDate checkoutDate = bookingInfoFromUser.getCheckoutDate();
Set<RoomBookingDetails> newBookingRoomsInfo = bookingInfoFromUser.getRoomBookingDetails();
Map<Integer, Integer> roomTotalRooms = new HashMap<>();
Map<Integer, Integer> roomTotalRoomsBooked = new HashMap<>();
List<BookingSummary> existingBookings = bookingRepository
.findByHotelIdAndCheckInDateBeforeAndCheckoutDateAfter(hotelId, checkInDate, checkoutDate);
RestTemplate template = new RestTemplate();
ResponseEntity<Object> hotelEntity = template.getForEntity("http://localhost:8383/hotel/" + hotelId,
Object.class);
Object hotelObj = hotelEntity.getBody();
ObjectMapper mapper = new ObjectMapper();
JsonNode hotelNode = mapper.convertValue(hotelObj, JsonNode.class);
hotelNode.withArray("hotelRooms")
.forEach(roomNode -> roomTotalRooms.put(roomNode.get("id").asInt(), roomNode.get("noRooms").asInt()));
existingBookings.forEach(existingBooking -> {
existingBooking.getRoomBookingDetails().forEach(bookedRoom -> {
if (roomTotalRoomsBooked.containsKey(bookedRoom.getHotelRoomId())) {
Integer existingKey = bookedRoom.getHotelRoomId();
Integer updateValue = roomTotalRoomsBooked.get(existingKey) + bookedRoom.getNoRooms();
roomTotalRoomsBooked.put(existingKey, updateValue);
} else {
roomTotalRoomsBooked.put(bookedRoom.getHotelRoomId(), bookedRoom.getNoRooms());
}
});
});
for (RoomBookingDetails newRoom : newBookingRoomsInfo) {
if (!((roomTotalRooms.get(newRoom.getHotelRoomId())
- roomTotalRoomsBooked.get(newRoom.getHotelRoomId())) >= newRoom.getNoRooms())) {
isAllRoomsAvailable = false;
}
}
if (isAllRoomsAvailable) {
persistedBooking = bookingService.save(persistedBooking);
} else {
throw new OptimisticLockException();
}
return persistedBooking;
}
我想要的是,如果两个用户同时尝试预订唯一可用的房间,那么只有一个用户应该能够成功。我不想锁定此服务,但让两个用户都尝试预订房间。但是,由于我展示的这种服务方法的检查,一个会失败。正如我所解释的,我无法进行乐观锁定,因为我没有包含特定入住和退房日期的可用房间信息的实体,我将在预订后更新。我检查可用性的唯一方法是获取特定房间类型的总房间数,并将其与该入住和退房日期已预订的房间总数进行比较。
到目前为止,我看到的所有解决方案都谈到了使用乐观方法进行处理,其中版本将针对我正在更新的行进行更改(但我没有在此处更新任何行)。我见过的另一种方法是悲观地锁定我正在更新的行(但正如我所说,我没有更新任何行)。
有没有办法解决这个并发问题,我让两个用户都尝试预订房间(一种乐观的方法),但服务方法中一个用户的可用性检查失败并为他们抛出异常。
如果我遗漏了任何信息,请随时告诉我,感谢您的帮助。
【问题讨论】:
标签: java spring oracle spring-boot spring-data-jpa