OrderSchedule,而Transactional則丟到新建的一個 OrderCancelService。透過排程呼叫Service來處理CANCEL事宜。private final int BATCH_SIZE = 10;
@Scheduled(cron = "0 */1 * * * ?")
public void expiredOrderScheduling(){
List<Order> orderList = orderCancelService.getExpiredOrderList();
if (orderList.isEmpty()) return;
log.info("Found {} expired orders", orderList.size());
int canceledCount = 0;
int batch = 1;
for (int i=0; i<orderList.size(); i+=BATCH_SIZE){
List<Order> ordersubList = orderList.subList(i, Math.min(i+BATCH_SIZE, orderList.size()));
// 藉由try-catch來防止某批次出問題而無法執行後續批次
try {
canceledCount += orderCancelService.expiredOrderScheduling(ordersubList);
batch++;
}catch (Exception e){
log.info("Failed to cancel {} batch", batch);
}
}
log.info("Successfully canceled {} orders", canceledCount);
}
JOING FETCH order.merchandise,也就是在Query過程,一併取出order本身關聯merchandise的實體並實例化。儘管我們可能設定Fetch Type是Lazy,但針對Merchandise這個實體則會 預先載入。select order from Order order JOIN FETCH order.merchandise WHERE order.status = 'UNPAID' AND order.create_time <= :expiredTime
// OrderCancelService.java
// 此函式由schedule呼叫
public List<Order> getExpiredOrderList(){
return orderDao.findAllExpiredUnpaidOrder(Instant.now().minus(Duration.ofMinutes(1)));
}
// 批次處理交易,回傳成功交易筆數給schedule
@Transactional
public int expiredOrderScheduling(List<Order> orderList){
int canceledCount = 0;
List<Merchandise> merchandiseList = new ArrayList<>();
for (Order order : orderList){
if (order.getStatus() != Order.STATUS.UNPAID) continue;
order.setStatus(Order.STATUS.CANCELED);
merchandiseList.add(restock(order));
canceledCount++;
}
orderDao.saveAll(orderList);
merchandiseDao.saveAll(merchandiseList);
return canceledCount;
}
// 補貨機制,由JOIN FETCH解決N+1問題,由交易函式呼叫
private Merchandise restock(Order order){
Merchandise merchandise = order.getMerchandise();
merchandise.setStock(merchandise.getStock() + order.getQuantity());
return merchandise;
}
本篇文章出自《每天學Java直到今年結束》Day223,大家可以到我的網站上查看~