2010-05-26 61 views
0

我对休眠比较新,所以请温和。我遇到了长时间运行的方法(〜2分钟长)以及更改存储在数据库中的对象上状态字段值的问题。下面的伪代码应该有助于解释我的问题。导致竞争状态的长时间运行方法

public foo(thing) { 
    if (thing.getStatus() == "ready") { 
     thing.setStatus("finished"); 
     doSomethingAndTakeALongTime(); 
    } else { 
     // Thing already has a status of finished. Send the user back a message. 
    } 
} 

该伪代码不应该采取太多的解释。我想doSomethingAndTakeALongTime()运行,但只有当它具有“准备就绪”的状态。每当doSomethingAndTakeALongTime()花费2分钟完成时,我的问题就会出现,并且事物状态字段的更改在它离开foo()之前不会持久保存到数据库。因此,另一个用户可以在这2分钟内发出请求,if语句将评估为true。

我已经尝试更新字段并手动刷新会话,但它似乎没有工作。我不知道该从这里做什么,并希望得到任何帮助。

PS:我的hibernate会话是由spring管理的。

+2

为了避免红鲱鱼:你知道你应该使用'equals()'来比较字符串吗? – BalusC 2010-05-26 22:06:25

+1

您的方法是否在交易环境中,例如春季声明式交易?如果是这样,那么冲洗将无法帮助,因为其他用户不会看到更改。 – mdma 2010-05-26 22:09:48

+0

@BalusC,是的,我知道这一点。我的真实代码不使用字符串;我刚刚创建了这个例子,并且不正确,为了您的观看乐趣。 :) – keeleyt83 2010-05-27 02:59:04

回答

2

基本上你需要让它运行在一个单独的Thread中,以使该方法立即返回。否则它将确实阻塞,直到长时间运行的任务完成。您可以将实体本身传递给线程,以便它可以更新状态本身。以下是一个简单的启动示例,使用简单的Thread

public class Task extends Thread { 
    private Entity entity; 
    public Task(Entity entity) { 
     this.entity = entity; 
    } 
    public void run() { 
     entity.setStatus(Status.RUNNING); 
     // ... 
     // Long running task here. 
     // ... 
     entity.setStatus(Status.FINISHED); 
    } 
} 

public synchronized void foo(Entity entity) { 
    if (entity.getStatus() == Status.READY) { 
     new Task(entity).start(); 
    } else { 
     // ... 
    } 
} 

随着一个enumStatus你甚至可以用一个switch语句,而不是一个if/else的。

switch (entity.getStatus()) { 
     case READY: 
      new Task(entity).start(); 
      break; 
     case RUNNING: 
      // It is still running .. Have patience! 
      break; 
     case FINISHED: 
      // It is finished! 
      break; 
    }    

对于正在运行的线程的一个更强大的控制,你可能要考虑ExecutorService代替。因此,您可以控制最大线程数并指定超时。

+0

嗯...我试图让foo()今天早些时候同步,它似乎没有工作。我所做的只是添加“同步”修改器。还有什么你必须做的,使其成为一个同步的方法? – keeleyt83 2010-05-27 03:22:00

+0

“同步”只有在您执行BalusC讨论的其他线程相关工作时才有所帮助。是你做的吗? – 2010-05-27 05:32:13

+0

@keeley:'synchronized'修饰符就是为了避免另一个线程在状态仍然设​​置为'RUNNING'的情况下进入该方法(因此您可能会冒险执行长时间运行的任务两次或更多)。它不会立即返回该方法。在另一个线程中执行长时间运行的任务将立即返回该方法。你试过了吗? – BalusC 2010-05-27 11:15:53

0

doSomethingAndTakeALongTime()正在做什么?是用于数据库操作还是只是执行一些业务逻辑?

如果它没有做任何数据库操作,并且你的status没有问题,那么你可以在调用该方法前坚持该对象。

如果它做一些数据库操作,那么你需要等待它。因此,即使你把线程,你需要等待该线程完成(使用thread.join()我们可以做到这一点)

事情是,在你坚持之前,你必须完成所有操作基于你的ORM对象吗?所以请尝试优化该方法的逻辑,使其在执行前保持执行。

谢谢。