【发布时间】:2014-05-29 20:33:45
【问题描述】:
编辑:错误是对的,别介意。
TL;DR:当我尝试在服务中的两个实例之间创建链接时,Hibernate 抱怨找不到其中一个,即使它确实存在。这似乎是在升级到 Grails 2.3.8 后开始发生的。
所以,我的应用程序是一个Call 跟踪应用程序。它有Users,为了知道一个User是否可用,我们有一个名为ResourceAvailability的类:
class ResourceAvailability {
def grailsApplication
Call callInstance
User resource
ResourceStatus resourceStatus
Date dateCreated
// ... constraints, etc ...
}
(没有从用户返回到 ResourceAvailability 的链接。)
当用户登录、接听电话或以其他方式更改状态时,他之前的可用性状态将从表中删除并创建一个新状态。这样我们就可以跟踪某人的准备时间,例如,在呼叫等待期间准备好,或者他们从接听电话以来的时间。
没有一堆错误处理代码,下面是 Call 控制器的 accept 操作的核心:
def accept(Long id, Long version) {
// All the Call stuff works fine...
def callInstance = Call.get(id)
callInstance.accept()
callInstance.save()
def user = springSecurityService.currentUser
// Clear out the user's existing Ready or Busy status
// TODO: Factor out into a service method
ResourceAvailability.where {
resource == user && (resourceStatus.statusDescription == "Ready" || resourceStatus.statusDescription == "Busy")
}?.each { it.delete() }
// Set new status. The error occurs in this method.
resourceAvailabilityService.setResourceStatus(user.id, 'Accepted', callInstance)
// redirect to view
}
还有setResourceStatus 方法:
void setResourceStatus(Long userId, String resourceStatusDescription, Call callInstance = null) {
def resource = User.read(userId)
ResourceStatus resourceStatus = ResourceStatus.findByStatusDescription(resourceStatusDescription)
/** HERE'S THE PROBLEM LINE **/
ResourceAvailability resourceAvailabilityInstance = new ResourceAvailability (
callInstance: callInstance,
resource: resource,
resourceStatus: resourceStatus
).save(flush: true, failOnError: true)
new ResourceHistory(resourceAvailabilityInstance).save(flush: true, failOnError: true)
}
尝试保存新的ResourceAvailability 时发生异常。 (如果我删除flush: true,它会在事务提交时发生在方法的末尾。)
作为参考,这里是例外:
ERROR errors.GrailsExceptionResolver - ObjectNotFoundException occurred when processing request: [GET] /CallLog/call/accept/17779
No row with the given identifier exists: [com.foobar.calls.User#0]. Stacktrace follows:
这似乎发生在我从 Grails 2.2.0 升级到 2.3.8 时。我仍然有 2.2.0 版本,并且相同的代码在那里工作。
我肯定引用的User(又名资源)存在。这不会在单元测试期间发生;我正在运行应用程序并登录。只是在调用此方法时,Hibernate 似乎失去了对用户的跟踪。
我已经对代码进行了加工,并且 User 实例存在于服务内部,在 new ResourceAvailability 行之前和之后。
编辑 所以我在登录 SQL 的情况下再次运行该方法,并注意到这一点:
2014-05-29 16:10:23,806 [http-bio-8080-exec-7] DEBUG hibernate.SQL - insert into resource_availability (version, call_instance_id, date_created, resource_id, resource_status_id) values (?, ?, ?, ?, ?)
2014-05-29 16:10:23,807 [http-bio-8080-exec-7] TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - 0
2014-05-29 16:10:23,807 [http-bio-8080-exec-7] TRACE sql.BasicBinder - binding parameter [2] as [BIGINT] - 17779
2014-05-29 16:10:23,808 [http-bio-8080-exec-7] TRACE sql.BasicBinder - binding parameter [3] as [TIMESTAMP] - Thu May 29 16:10:23 CDT 2014
2014-05-29 16:10:23,808 [http-bio-8080-exec-7] TRACE sql.BasicBinder - binding parameter [4] as [BIGINT] - 30
2014-05-29 16:10:23,808 [http-bio-8080-exec-7] TRACE sql.BasicBinder - binding parameter [5] as [BIGINT] - 1
2014-05-29 16:10:23,826 [http-bio-8080-exec-7] DEBUG hibernate.SQL - select user0_.id as id24_0_, user0_.version as version24_0_, user0_.account_expired as account3_24_0_, user0_.account_locked as account4_24_0_, user0_.enabled as enabled24_0_, user0_.first_name as first6_24_0_, user0_.last_name as last7_24_0_, user0_.`password` as password8_24_0_, user0_.password_expired as password9_24_0_, user0_.resource_level_id as resource10_24_0_, user0_.username as username24_0_ from user user0_ where user0_.id=?
2014-05-29 16:10:23,826 [http-bio-8080-exec-7] TRACE sql.BasicBinder - binding parameter [1] as [BIGINT] - 0
为什么它在插入后做select,为什么它使用user.id of 0???
编辑将我的 Grails Hibernate 插件升级到 3.6.10.15。没有解决问题:/
【问题讨论】:
-
你为什么要传入
User的id,然后再传入read,你已经拥有来自springSecurityService.currentUser的用户实例? -
@dmahapatro 我想也许该实例在服务事务结束时已关闭或丢失,所以我尝试将其更改为这个,但还没有改回来。
标签: hibernate session grails transactions