我引入了一个 TransactionService,我在控制器中使用它来执行乐观事务。它应该
- 尝试执行给定的事务(= 关闭)
- 如果失败则回滚
- 如果失败再试一次
它基本上看起来像这样:
class TransactionService {
transactional = false // Because withTransaction is used below anyway
def executeOptimisticTransaction(Closure transaction) {
def success = false
while (!success) {
anyDomainClass.withTransaction { status ->
try {
transaction()
success = true
} catch(Exception e) {
status.setRollbackOnly()
}
}
}
}
}
它有点复杂,例如它在再次尝试之前使用不同的 Thread.sleep 并在某个阶段中止,但这在这里并不重要。它是由控制器调用的,控制器传递事务以作为闭包安全执行。
我的问题:当服务由于并发更新而遇到 org.hibernate.StaleObjectStateException 时,它会不断重试,但异常永远不会消失。
我已经尝试了不同的方法,例如在控制器传递的事务中重新附加域类,清除服务或控制器中的会话,但它没有帮助。我缺少什么?
我应该注意到,当我尝试在使用 status.createSavepoint() 调用 transaction() 之前插入 savePoint 时,出现“事务管理器不允许嵌套事务”的错误。我尝试这样做是因为我还怀疑存在错误,因为事务是从控制器传递到服务的,并且我需要启动一个新的/嵌套事务来避免它,但正如错误所示,这在我的情况下是不可能的。
或者也许将事务作为闭包传递是问题所在?
我认为 .withTransaction 之前使用的域类并不重要,是吗?
这本身并不是封闭,但我相信transaction
里面有一些陈旧的变量引用。
如果您尝试仅传递在执行时重新读取其对象的闭包该怎么办?喜欢
executeOptimisticTransaction {
Something some = Something.get(id)
some.properties = aMap
some.save()
}
我不认为在 Hibernate 中不重新读取对象就可以“刷新”它。
是的,您在哪个类上调用 .withTransaction() 并不重要。
对于更新计算的总数/评级的示例,数据重复本身就是一个问题。我宁愿:
- 创建一个(Quartz)作业,该作业将根据某些“脏”标志更新评级 - 这可能会节省一些 DB CPU 以更新时间成本;
- 或者用 SQL 或 HQL 执行,例如
Book.executeQuery('update Rating set rating=xxx')
这将使用最新的评级。如果您正在针对重负载进行优化,那么您无论如何都不会以 Groovy 方式完成所有操作。不要在 Grails 中保存评级对象,而只能读取它们。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)