Grails 2.5.5交易问题。
我们有一个get Balance调用API调用,它是一个简单的 Controller ,可以调用一些服务。它做两件事,用其余额返回客户帐户并更新客户 session (例如保持 Activity )。
问题是,当客户端同时调用两次getBalance时,总是抛出一个异常,即使在save()中,我们有failOnError:false(并且尝试四处寻找也无济于事,请参见下文)。如果其他任何人当前正在刷新 session ,我们需要refreshSession静默失败,并返回帐户余额,就好像什么都没出错。我们无法弄清楚如何做到这一点,因为failOnError:false并尝试catch不起作用,并且丢弃或刷新均无效。
SessionService:
boolean refreshSession( Session aSession ) {
if ( aSession != null ) {
aSession.lastUpdatedAt = new Date()
aSession.save(flush:true, failOnError: false) // line 569. This always fails on error even with failOnError set to false.
return true
}
return false
}
这是我们得到的错误:
org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException: Object of class [com.xxx.Session] with identifier [23]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xxx.Session#23]
at com.xxx.services.SessionService$$EQ2LbJCm.refreshSession(SessionService.groovy:569)
at com.xxx.getBalance(AccountController.groovy:56)
如果failOnError = false,它将如何失败?
session 服务由未定义事务性质的 Controller 调用。
Controller :
def getBalance() {
try {
:
Session session = sessionService.getSession(payload.token)
sessionService.refreshSession(session) // this updates the session object
def accountResult = accountService.getBalance(session.player) // line 59: this returns a structure of account domain objects
// which have a balance and currency etc. It is ready only!
render(status: 200, contentType: 'application/json') {
[
'result' : 0,
'accounts': accountResult.accounts
}
return
} catch (Exception e) {
renderError(ERROR, e.toString())
log.error("getBalance API Error:" + e.toString(), e)
}
我们尝试的是:
有趣的是,最后一行将异常发生的行更改为下一行(读取帐户的帐户,该帐户不写入,仅读取)
org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException: Object of class [com.xxx.Session] with identifier [23]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xxx.Session#23]
at com.xxx.getBalance(AccountController.groovy:59)
@NotTransactional
boolean refreshSession( Session aSession ) {
if (aSession != null) {
try {
aSession.lastUpdatedAt = new Date()
aSession.save(failOnError: false)
} catch (Exception e) {
aSession.discard()
aSession.refresh()
} finally {
return true
}
}
return false
}
@Transactional
boolean refreshSession( long id ) {
Session session = Session.get(id)
if (session != null) {
try {
session.lastUpdatedAt = new Date()
session.save(flush: true, failOnError: false)
} catch (Exception e) {
println("XXX got exception:" + e.message)
session.discard()
} finally {
return true
}
}
return false
}
由于原始异常,此操作将失败。似乎不可能忽略grails中的写入失败。危险地,即使捕获到异常,并显示“XXX got exception”,也没有明显的原因再次抛出该异常。
我对使所有内容都变为NonTransaction的理解是,就像具有autoCommit:true一样-每个数据库更新都将立即发生,并且如果某件事失败,它将不会回滚其他事情吗?
有任何想法吗?
最佳答案
我认为您需要 .withNewTransaction
boolean refreshSession( long id ) {
Session.withNewTransaction {
Session session = Session.get(id)
if (session != null) {
try {
session.lastUpdatedAt = new Date()
session.save(flush: true, failOnError: false)
} catch (Exception e) {
println("XXX got exception:" + e.message)
session.discard()
} finally {
return true
}
}
}
return false
}
在提供的链接中,它正在返回最新状态,因为该元素可能在过程中在被记录并尝试对其进行检查时已被更新。您还可以查看
isDirty
和 getPersistentValue
。个人认为使用NewTransaction进行包装可以解决此问题。您说要放弃第二次点击,但是实际上那不是最新有效的lastUpdatedAt吗?
关于grails - grails 2.5:failOnError:false始终始终在出错时失败。如何不因错误而失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40567819/