2010-05-26 97 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對象嗎?所以請嘗試優化該方法的邏輯,使其在執行前保持執行。

謝謝。