2012-12-26 28 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