我有一个grails应用程序,它依赖于一个同步块作为服务。当我在windows上运行时,同步按预期工作,但当我在ams linux上运行时,会得到一个StaleObjectStateException。
这个问题在下面的例子中重现。
class TestService {
private final Object $lock = new Object[0];
TesteSync incrementa() {
synchronized ($lock) {
TesteSync t = TesteSync.findById(1)
t.contador++
t.save(flush: true)
Thread.sleep(10000)
return t
}
}
}
在我的理解中,这个异常发生是因为多个线程试图保存同一个对象。这就是为什么我要使用同步块。
Linux java:- java版本"1.7.0_85"
- OpenJDK Runtime Environment (amzn-2.6.1.3.61.)amzn1-x86_64 u85-b01)
- OpenJDK 64位Server VM (build 24.85-b03, mixed mode)
- java版本"1.7.0_79"
- Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
- Java HotSpot(TM) 64位Server VM (build 24.79-b02, mixed mode)
什么线索吗?
谢谢
你是对的,为什么你得到StaleObjectStateException。
如果您正在寻找的是悲观锁定(在任何给定时间只允许一个事务访问数据),那么您可以使用域类lock()方法:
class TestService {
static transactional = true
TesteSync incrementa() {
TesteSync t = TesteSync.lock(1)
t.contador++
return t.save()
}
}
你可以在这里了解更多关于Grails悲观锁的信息。
PS: Grails服务默认是事务性的。但是在我的示例中,我显式地将服务设置为事务性,以引起您的注意:当事务提交时,锁将由Grails自动释放。我还删除了刷新,因为在事务提交时数据会刷新。如果你从一个没有显式设置为@Transactional的控制器方法中执行此操作,那么你将需要flush。提示:当你按ID查询时,你可以这样做…
SomeDomainClass.get(1)
…而不是这个…
SomeDomainClass.findById(1)