我有一个Spring控制器和两个方法,一个准备订单数据供用户编辑,另一个方法是从表格(POST)返回最新的订单信息更改。
现在我想让一些程序像OptiMistic Locking
一样工作而不在数据库中添加版本列。因为客户端在会话到期之前花了一些时间来编辑订单,所以我必须使用post方法确保客户首次打开订单编辑页面时订单仍处于相同状态
所以我在加载订单编辑页面之前添加orderStatus
属性来保存原始状态,并在保存订单编辑时与DB的最新状态进行比较,如下所示:
@RequestMapping("/order")
@Controller
public class OrderController{
private String orderStatus;
@RequestMapping(value = "/{orderId}/edit", method = RequestMethod.GET)
public String prepareOrderEditForm(....){
....
// remember the original status
orderStatus = Order.getLatestStatus(orderId);
}
@RequestMapping(value = "/processEdit", method = RequestMethod.POST)
public String prepareOrderEditForm(....){
....
String currentOrderStatus = Order.getLatestStatus(orderId);
// compare most recent status with the original status
if(currentOrderStatus.equals(orderStatus) == false){
....//something is wrong, someone may be already edit the order
return "failed";
}else{
orderService.merge(order);
orderStatus = order.getNewStatus();
}
return "updated";
}
}
我理解这个设计不像数据库的乐观锁定那样健壮,它可能会忽略执行DML的时间,这里的orderStatus也应该使用getter / setter作为java bean。所以请排除上述问题,但只将范围放在此控制器中
我的问题是,由于Spring MVC在JSP Servlet这样的单线程中运行,当多个用户登录到spring web应用程序并编辑相同的顺序时会出现任何问题,因此该控制器类中的orderStatus以某种方式由多个用户交织在一起(并发问题)?
答案 0 :(得分:0)
JSP和Spring MVC都不是单线程的。
您应该始终尝试不在控制器方法中更改实例/静态变量。
修改强>
我应该提到会话线程安全只有在你将Spring MVC抽象控制器的synchronizeOnSession设置为true时才会起作用(默认为false)。
在您的情况下,您可以:
1)在定义控制器的spring应用程序上下文中将synchronizeOnSession设置为true。
2)从Spring的AbstractController扩展并覆盖handleRequestInternal方法。
3)在handleRequestInternal中调用request.getSession()。setAttribute(" orderStatus")