我们有一个HTTP端点,需要很长时间才能运行,也可以由用户同时调用。作为此请求的一部分,我们更新同步块内的模型,以便其他(可能是并发的)请求获取该更改。
E.g。
MyModel m = null;
synchronized (lockObject) {
m = MyModel.findById(id);
if (m.status == PENDING) {
m.status = ACTIVE;
} else {
//render a response back to user that the operation is not allowed
}
m.save(); //Is not expected to be called unless we set m.status = ACTIVE
}
//Long running operation continues here. It can involve further changes to instance "m"
synchronized 块的原因是确保即使并发请求也能获取最新状态。但是,在请求完成之前,基础JPA不会提交我的更改(m.save())。由于这是一个长时间运行的请求,我不想等到请求完成后仍然希望确保其他呼叫者收到状态更改的通知。我试着调用“m.em()。flush(); JPA.em()。getTransaction()。commit();”在m.save()之后,但是这使得事务不可用于后续操作作为同一请求的一部分。我可以给出“JPA.em()。getTransaction()。begin();”让Play从那时开始处理交易?如果没有,处理这个用例的最佳方法是什么?
更新 根据回复,我修改了我的代码如下:
MyModel m = null;
synchronized (lockObject) {
m = MyModel.findById(id);
if (m.status == PENDING) {
m.status = ACTIVE;
} else {
//render a response back to user that the operation is not allowed
}
m.save(); //Is not expected to be called unless we set m.status = ACTIVE
}
new MyModelUpdateJob(m.id).now();
在我的工作中,我有以下几行:
doJob() {
MyModel m = MyModel.findById(id);
print m.status; //This still prints the old status as-if m.save() had no effect...
}
我错过了什么?
答案 0 :(得分:2)
将更新代码放入作业中
new MyModelUpdateJob(id).now().get();
因此,更新将在作业结束时提交的另一个事务中完成
答案 1 :(得分:0)
ouch,只要添加更多播放服务器,就会遇到麻烦。您可能希望在示例中使用乐观锁定,或者我建议不要使用悲观锁定.... ick。
但是,查看您的代码,可能会阅读文章Building on Quicksand。在这种情况下,我不确定你是否需要同步块...尝试追求幂等。
在你的情况下,如果 1.用户1和用户2都调用该方法并且它处于挂起状态,然后它进入活动状态(Idempotent) 如果用户1或用户2获胜,那么就像你有同步块一样。
我确信你有一个更复杂的场景没有在这里显示,但请阅读文章建立在Quicksand上,因为它真的改变了传统的思维方式,是谷歌和亚马逊以及超大规模系统的运作方式。
跨播放服务器的分布式事务的另一个选择是zookeeper,大型的大型nosql人使用但仅作为最后的手段;);)
后, 迪安