我正在使用 Quarkus React 和 Hibernate React 以及 Postgresql 数据库来构建非阻塞 Web 应用程序。
以下代码应返回数据库中存储的所有车辆对于特定计划行程的可用性。可用性源自表格车辆(车辆是否有缺陷)、预订(是否已经有该车辆的有效预订)和计划的乘车(是否计划有不同的乘车并且与请求的乘车时间段重叠)。
我想出了以下解决方案:
@GET
@Path("/availabilities")
public Uni<List<VehicleAvailability>> vehicleAvailabilitiesForRide(@QueryParam("rideId") String rideId) {
return PlannedRide.<PlannedRide>findById(rideId).map(Unchecked.function(ride -> {
if (ride == null) {
throw new NotFoundException();
}
return ride;
})).flatMap(ride -> {
Uni<List<VehicleReservation>> reservationsUni = VehicleReservation.findReservationsInPeriod(ride.getStart(), ride.getEnd());
Uni<List<PlannedRide>> plannedRidesUni = PlannedRide.findRidesInPeriod(ride.getStart(), ride.getEnd());
return Uni.combine().all().unis(reservationsUni, plannedRidesUni).asTuple().flatMap(tuple -> {
Uni<List<Vehicle>> vehiclesUni = Vehicle.findAll().list();
List<VehicleReservation> reservations = tuple.getItem1();
List<PlannedRide> plannedRides = tuple.getItem2();
return vehiclesUni.map(vehicles -> vehicles.stream().map(vehicle -> {
if (vehicle.isDefective()) {
return new VehicleAvailability(vehicle, Availability.DEFECTIVE);
}
//check reservation
for (VehicleReservation reservation : reservations) {
if (Objects.equals(reservation.getVehicle().getId(), vehicle.getId())) {
//vehicle is reserved in period
if (Objects.equals(reservation.getPlannedRide().getId(), ride.getId())) {
//reserved for current ride
return new VehicleAvailability(vehicle, Availability.RESERVED);
} else {
return new VehicleAvailability(vehicle, Availability.NOT_AVAILABLE);
}
}
}
if (plannedRides.stream().anyMatch(iterRide -> !Objects.equals(ride.getId(), iterRide.getId()))) {
return new VehicleAvailability(vehicle, Availability.POTENTIALLY_AVAILABLE);
}
return new VehicleAvailability(vehicle, Availability.AVAILABLE);
}));
});
}).map(Stream::toList);
}
首先,我必须找到所请求的行程发生的时间段。然后,我使用 Uni#combine() 获取该时段的预订和游乐设施。之后,对于每辆车,我都会返回一个具有适当状态的新 DTO。
不幸的是,我收到一个 Illegal pop() with non-matching JdbcValuesSourceProcessingState 异常,我不知道如何解决它。
经过一番谷歌搜索后,我发现会话不能同时使用,我使用 Munity.SessionFactory#openSession()、#withSession() 和 #withTransaction 为每个数据库访问创建了一个新会话。然而问题仍然存在:(。但是,当我不使用 Uni#combine 方法,而只映射plannedRidesUni 或reservationsUni 的结果时,代码工作正常,但我确实需要它们用于不同的状态。
我认为您不能将
.combine().all()
与 Hibernate Reactive 会话一起使用。问题是会话执行的操作的顺序必须是可预测的。
解决方案是以可预测的顺序链接 uni。 您可以在此答案中找到一个示例:Quarkus 反应式风格如何在非 REST 端点中使用 @ReactiveTransactional 注释