【问题标题】:Play 1.2.3 framework - Right way to commit transactionPlay 1.2.3 框架 - 提交事务的正确方法
【发布时间】:2012-02-14 13:53:20
【问题描述】:

我们有一个 HTTP 端点,它需要很长时间才能运行,也可以由用户并发调用。作为此请求的一部分,我们在同步块内更新模型,以便其他(可能并发的)请求获取该更改。

例如

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...
}

我错过了什么?

【问题讨论】:

    标签: jpa playframework


    【解决方案1】:

    将您的更新代码放入作业中调用

    new MyModelUpdateJob(id).now().get();
    

    因此更新将在作业结束时提交的另一个事务中完成

    【讨论】:

    • 谢谢。我已根据您的回复更新了我的帖子。简而言之,Job 似乎没有获得行的更新,并且仍然看到旧状态。
    • @Ananth 你检查过Play documentation on asynchronous HTTP吗?在我看来,双重作业设置应该可以工作,前提是您还告诉您的控制器方法您要等待作业完成。
    • 对播放控制器的调用是一个事务。因此,当 http 请求/响应完成时,您将在控制器中看到所做的修改。在您的工作中,您看不到控制器中完成的事情,因为该方法尚未完成。您必须基于此重新考虑您的代码。你还得注意迪恩说的话。出于商业目的使用同步块不是一个好的做法,这不会扩展
    【解决方案2】:

    哎呀,一旦你添加更多的游戏服务器,你就会遇到麻烦。您可能想在您的示例中使用乐观锁定,或者我建议不要使用悲观锁定....ick。

    但是,查看您的代码,也许可以阅读文章Building on Quicksand。我不确定在那种情况下你是否需要一个同步块......尝试幂等。

    在你的情况下,如果 1. 用户 1 和用户 2 都调用该方法并且它处于挂起状态,然后进入活动状态(幂等) 如果用户 1 或用户 2 获胜,那就像你有同步块一样。

    我相信您有一个更复杂的场景,这里没有显示,但请阅读这篇文章 Building on Quicksand,因为它确实改变了传统的思维方式,并且是谷歌和亚马逊以及超大规模系统的运作方式。

    另一个用于跨游戏服务器的分布式事务的选项是 zookeeper,大型 nosql 家伙仅将其用作最后的手段;) ;)

    后来, 院长

    【讨论】:

      猜你喜欢
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多