2012-12-26 26 views
3

我有一個Grails服務方法,負載,我只希望一個用戶在一次能夠運行。我嘗試過使用Grails悲觀鎖,但它只是有時可行。在我的控制器中,我有:在多用戶環境中使grails服務方法原子化

try { 
    def country = Country.lock(id) 
    myService.load(country) 
} catch (CannotAcquireLockException ex) { 
    flash.message = "Another user is modifying ${Country.get(id)}" 
} 

什麼是使myService原子的加載方法的最佳方式是什麼?

如果我想讓兩個方法成爲原子(當一個正在執行時,兩個都不能執行)怎麼辦?

我服務的方法:

def load(id) { 
    def country = Country.get(id) 
    country.states.each { 
     ... 
     it.save(flush: true) 
    } 
} 

添加synchronized關鍵字來此方法將導致在保存StaleObjectStateException。

回答

2

默認情況下,Grails服務是單例服務,可以解決部分問題。你也應該同步,達到你想要你的服務方法:

def synchronized load(country) { ... } 
+0

當我添加synchronized關鍵字,我得到一個StaleObjectStateException當我保存。我編輯了我的帖子,以顯示我的加載方法的更多細節。 – Alison

+0

從以下文檔:http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html,我解釋同一個類的兩個方法上的同步關鍵字將阻止運行時,一個已經開始。那是對的嗎? – Alison

+0

+1,它幫助我確定java的ReentrantLock是我應該使用的。我仍然很好奇爲什麼同步拋出這個異常。 – Alison

1

這可以解決與使用ReentrantLock一個普通的Java同步問題。我可以使用isLocked來返回一個錯誤,而不是讓用戶等待鎖來做同樣的事情。

2

您可以使用@synchronized註釋與自定義同步鎖定。這樣你不會同步this(整個服務類),只有給定的方法。

代碼示例

class MyCustomService 

private final myLock = new Object() 

@Synchronized("myLock") 
def myRunOneAtATimeMethod(int x, int y) 
    return x+y 

更多關於同步:http://groovy.codehaus.org/gapi/groovy/transform/Synchronized.html