给出以下代码,该代码在Spring Boot中以JSON形式接收带有web商店订单的请求。订单应移交给处理订单的方法processJsonOrder
。在移交之后,web服务应该返回OK给客户端。processJsonOrder
中的处理应该是异步的,不能阻塞返回到客户端。
@RestController
public class WebShopOrderController {
@Autowired
private OrderService orderService;
@PostMapping(value = "/wc-order")
public void getWcOrder(@RequestBody String jsonOrder, @RequestHeader Map<String, String> headers) {
log.info("order received");
// should be done async
processJsonOrder(jsonOrder);
return;
}
}
但是在processJsonOrder
中处理的jsonOrder需要逐一处理。也许是通过队列,或者在Spring中有一个很好的解决方案。这个想法是当在processJsonOrder
中执行订单时,jsonOrders正在等待。目前,当两个订单更新在几秒钟内到达时,由于处理jsonOrder
的线程还没有到达提交点,因此processJsonOrder
会将订单插入数据库两次。在orderService
中有一些代码来检查数据库级别的重复,但这并不总是有帮助。
OrderService.java
@Service
public class OrderService {
@Async
@Transactional
public void processJsonOrder(WoocommerceOrder wcOrder) {
// performing business logic
}
}
我希望有一个优雅的解决方案,或者也许做processJson顺序异步是错误的方法。重要的是,调用客户端立即得到应答,但随后异步处理订单,但是一个接一个。
您试图对代码做的事情称为达到互斥以避免竞争条件-两个或多个进程或线程同时到达代码的关键段并试图读取和/或更新相同的数据块,这可能会导致错误或错误。在java中,有一个内置的特性来避免这种问题:synchronized
关键字。
首先,在控制器上配置线程:
@RestController
public class WebShopOrderController {
@Autowired
private OrderService orderService;
@PostMapping(value = "/wc-order")
public void getWcOrder(@RequestBody String jsonOrder, @RequestHeader Map<String, String> headers) {
log.info("order received");
// Will be done async
new Thread(() -> processJsonOrder(jsonOrder)).start();
return;
}
}
然后,只需在@Service
方法上使用synchronized
关键字:
@Service
public class OrderService {
@Transactional
public synchronized void processJsonOrder(WoocommerceOrder wcOrder) {
// Only one Thread at a time will be allowed to enter this area.
// performing business logic
}
}