tl:dr;这是一个有点涉及的问题,欢迎任何建议,感谢提前阅读:)
我的同事和我一直在努力在我们的批处理应用程序中的一个奇怪的行为。我们最近将它从Grails 1.3.7升级到2.1
堆栈跟踪显示以下错误:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException:
Cannot insert the value NULL into column 'date_created',
table 'dev.dbo.notification_log'; column does not allow nulls. INSERT fails.
...
[quartzScheduler_Worker-1] [||] ERROR hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: null id in com.virtuwell.domain.NotificationLog entry (don't flush the Session after an exception occurs)
at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1891)
at org.quartz.core.JobRunShell.notifyJobListenersComplete(JobRunShell.java:352)
at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:546)
[quartzScheduler_Worker-1] [||] ERROR listeners.SessionBinderJobListener - Cannot flush Hibernate Sesssion, error will be ignored
org.hibernate.AssertionFailure: null id in com.virtuwell.domain.NotificationLog entry (don't flush the Session after an exception occurs)
at org.quartz.core.QuartzScheduler.notifyJobListenersWasExecuted(QuartzScheduler.java:1891)
at org.quartz.core.JobRunShell.notifyJobListenersComplete(JobRunShell.java:352)
at org.quartz.core.JobRunShell.run(JobRunShell.java:223)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:546)
这是特定域对象(NotificationLog)的代码
class NotificationLog implements Serializable{
Date dateCreated
Notification notification
NotificationDeliveryState deliveryState
String message
static mapping = {
message type: 'text'
}
}
然而,奇怪的是,这个错误并不是每次域对象持久化时都发生,并且在代码中只有一个地方对象持久化了,如下所示:
class NotificationLogService {
boolean transactional = true
def logNotification(Notification notification, message, deliveryState) {
def notificationLog = new NotificationLog(
notification: notification,
deliveryState: deliveryState,
message:message
)
try{
notificationLog.save(failOnError:true)
} catch (Exception e) { // Failure to save a notificationLog should not rollback the calling transaction
log.error "NotificationLog State:[$deliveryState] for notification:${notification?.id} did not save. Errors: ${notificationLog?.errors}, Message:$message", e
}
}
}
我们在下面的SO问题中发现了一个解决方案,通过将其添加到域对象
,我们不再定期在日志中看到错误。static mapping = {
autoTimestamp true
}
但这并不是我们看到的唯一一个周期性保存失败的域(因此,我需要将映射添加到其他域),如果这真的是dateCreated
在Grails 2.1中正常工作所必需的,我需要将它添加到更多的域!
更糟糕的是,我不能在单元或集成测试中重现它,它只发生在我们运行的Dev和QA实例上。
所以,2个问题:
有人知道为什么这个错误可能会周期性发生吗?
如果没有,是否有一种方法我可以全局将此
autoTimestamp true
映射添加到我的所有项目的域对象(我一直无法找到如何添加它的文档,除了将其设置为false
)
相关SO问题:Grails 2.0中的dateCreated, lastUpdated字段
相关Grails邮件列表讨论http://grails.1312388.n4.nabble.com/dateCreated-lastUpdated-in-Grails-2-0-td4337894.html
关于autoTimestamp GORM属性的相关Grails文档http://grails.org/doc/latest/guide/GORM.html eventsAutoTimestamping
回答这两个问题:
-
EDIT尝试
flush: true
而save
,否则autoTimestamp true
是最后的手段。我还没有调查这个问题的原因。 -
您可以在
Config.groovy
中设置此属性,使其适用于所有domain
类。grails.gorm.default.mapping = { autoTimestamp true //or false based on your need }
您是否尝试在创建新的NotificationLog时手动插入日期?这样的:
class NotificationLogService {
boolean transactional = true
def logNotification(Notification notification, message, deliveryState) {
def notificationLog = new NotificationLog(
dateCreated: new Date(),
notification: notification,
deliveryState: deliveryState,
message:message
)
try{
notificationLog.save(failOnError:true)
} catch (Exception e) { // Failure to save a notificationLog should not rollback the calling transaction
log.error "NotificationLog State:[$deliveryState] for notification:${notification?.id} did not save. Errors: ${notificationLog?.errors}, Message:$message", e
}
}
}