我正在使用jMeter对我的grails应用程序进行性能测试。在并发用户访问该站点的情况下,有时我在日志中看到以下错误:
Excepton:行被另一个事务更新或删除(或 unsaved-value mapping不正确)[com.mypack.app.MyClass#1113]
如何在未来修复并避免这些错误?
以下是完整堆栈:
->> 245 | doCall in com.mypack.app.MyController$_save_closure3_closure8
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 225 | save in com.mypack.app.MyClontroller
| 195 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run . . . in java.lang.Thread
答案 0 :(得分:2)
Grails默认为乐观锁定,它假定并发更新很少或没有,或者当它们发生时,您有适当的策略来解决问题。这与许多源控制系统类似,其中两个用户可以编辑一个文件,但如果编辑重叠则存在必须手动解决的冲突。
通常,解决并发编辑问题是不切实际的。如果您在MyClass
实例中更改了一个属性并且我更改了另一个属性,理论上我们可以将这两个更改合并为一个新记录,但是如果您的更改会影响我在看到它时所做的更改会怎么样?第一λ
为了简单起见,如果您允许同时进行修改并且没有合并'策略,你应该使用显式锁定。这确实会影响性能,但如果您只锁定特定的域类或特定的工作流,则影响应该很小,特别是如果记录保持锁定的时间很短。
但是锁定网络应用程序很棘手。当你开始编辑'时需要锁定。工作流并加载域类实例以填充该GSP,并在用户在浏览器中进行更改时保持记录锁定,并在“更新”时释放锁定。行动结束(成功与否)。 Grails不支持此功能,因为每个请求都有自己的Hibernate Session
并且在每个请求结束时关闭它(以及它会释放锁定的Connection
) 。如果你要实现这一点,你必须确保如果没有调用更新操作(或在最大允许时间之后调用),则释放锁以允许其他人编辑。
因此,您要回到手动合并策略(或Webflow或类似的东西)。您可以通过在version false
块中添加mapping
来删除域类中的自动版本检查。然后在您的更新操作中,将检查过时版本的块转换为查看版本但也更改字段的自定义代码,并使用对您的域类有意义的任何逻辑来解析/合并并发编辑。