我有一个 Order 类,其中包含订单行列表:
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID uuid;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<OrderLine> orderLines;
}
还有
public class OrderLine {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID uuid;
@ManyToOne
@JoinColumn(name = "order_uuid", referencedColumnName = "uuid")
private Order order;
@Enumerated(EnumType.STRING)
private OrderLineStatus status;
}
当我验证订单时,我会为他的每行发送一个事件,因此每行都会单独验证。其他应用程序处理这些事件并发回每行的验证事件。当我的应用程序捕获这些验证事件时,它会更新线路状态,然后检查它是否是最后一个要处理的线路。如果它是最后一个要处理的订单,则会更新订单状态。
到目前为止我已经做到了:
public void handleEvent(Event event) {
OrderLine orderLine = orderLineService.findById(event.getOrderLineUuid());
if (!OrderLineStatus.VALIDATED.equals(orderLine.getStatus())
&& !OrderStatus.VALIDATED.equals(orderLine.getOrder().getStatus())) {
// Update using @Modifying
orderLineService.updateStatusAndError(
OrderLineStatus.VALIDATED, null, orderLine.getUuid());
checkIfLastOrderLine(orderLine.getOrder());
}
public void checkIfLastOrderLine(final Order order) {
// A pessimistic read lock is set on countByStatusAndOrderUuid
long stillProcessingCounter = orderLineService
.countByStatusAndOrderUuid(OrderLineStatus.PENDING_FOR_VALIDATION, order.getUuid());
if (stillProcessingCounter == 0) { // All lines processed
// Update order status
// Do other stuff that need to be done only once
}
}
但是当我测试它时,我的订单状态会更新多次。我还尝试在 checkIfLastOrderLine 上进行同步,但我们有多服务器服务,因此任何服务器都可以处理任何事件。
我正在考虑在我的订单上实施一个计数器来跟踪经过验证的订单行,但我不知道这是否是一个好主意。
感谢您的帮助!
我会尝试在
OrderStatus
字段上同步。
在订单存储库中添加将更新订单状态的方法(如果当前状态为
PENDING_FOR_VALIDATION
(或您使用的任何枚举值))。此方法返回许多修改的行。
@Query("update order set order_status = ? where orderId = ? and order_status = 'PENDING_FOR_VALIDATION'", nativeQuery = true)
@Modifying
int updateOrderStatus(OrderStatus orderStatus, UUID orderId);
这意味着,
updateOrderStatus
应该仅针对单个事件处理程序返回 1
。
我相信它应该与 stillProcessingCounter
一起使用,如下
if (stillProcessingCounter == 0 and updateOrderStatus(VALID, order.getUUID() == 1) {
// do some logic that should be executed only once
}