Grails 2.1 dateCreated间歇性地保存域名

时间:2013-04-24 21:47:56

标签: grails gorm grails-2.0 datecreated

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问题中找到了一个'hack'解决方法,我们不再定期看到日志中的错误,只需将其添加到域对象

static mapping = {
    autoTimestamp true
}

但这不是我们在SAME周期性保存失败时看到的唯一域(因此,我需要将映射添加到其他域),如果dateCreated真正需要它在Grails 2.1中,我需要将其添加到更多域中!

更糟糕的是,我无法在单元或集成测试中重现它,它只发生在我们正在运行的Dev和QA实例上。

所以, 2个问题:

  1. 有谁知道为什么会出现这种错误?

  2. 如果没有,是否有办法全局将此autoTimestamp true映射添加到我项目的所有域对象中(我一直无法找到有关如何使用的文档添加它,除了将其设置为false

  3. 相关SO问题: dateCreated, lastUpdated fields in Grails 2.0

    相关Grails Maillist讨论 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

2 个答案:

答案 0 :(得分:3)

回答这两个问题:

  1. 编辑flush: true时尝试save,否则autoTimestamp true是最后的选择。我没有研究找出这个问题的原因。

  2. 您可以在Config.groovy中设置此属性,使其适用于所有domain类。

    grails.gorm.default.mapping = {
        autoTimestamp true //or false based on your need
    }
    

答案 1 :(得分:0)

您是否尝试在创建新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
    }


}

}