【问题标题】:Grails 2.1 dateCreated null intermittently on domain saveGrails 2.1 dateCreated 在域保存时间歇性地为空
【发布时间】:2013-04-24 21:47:55
【问题描述】:

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
}

但这不是我们看到的唯一一个相同的定期保存失败的域(因此,我需要将映射添加到其他域),如果这确实是dateCreated 正常运行所必需的Grails 2.1,我需要将它添加到更多域!

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

所以,2 个问题:

  1. 有人知道为什么这个错误会周期性发生吗?

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

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

相关 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

【问题讨论】:

    标签: grails grails-orm grails-2.0 datecreated


    【解决方案1】:

    回答这两个问题:

    1. 编辑尝试flush: truesave否则autoTimestamp true是最后的手段。我没有研究找出这个问题的原因。

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

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

    【讨论】:

    • 非常感谢您的第二个回答!不过,我不确定我是否理解您对第一个问题的回答,您能否澄清一下“我们知道这种行为是常年存在的”是什么意思?这是每年在整个 grails 中都会发生的事情吗?还是您的意思是“周期性”或“间歇性”,因为我知道这不一致,因此需要从“最后的手段”解决方案开始并从那里开始工作?
    • 抱歉造成误会。我在回答中掺入了其他东西。现在看我的编辑。如果需要,我可以尝试进行相同的测试。
    【解决方案2】:

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

    }

    【讨论】:

    • 我没试过。我认为它会像我演示的 mapping 添加一样有效,但是该解决方案有两个问题:1)GORM 应该已经为我这样做了,并且偶尔会这样做,以及 2)如果我要修复我的其他失败的域保存,我需要找到很多保存这些域的地方并应用此修复程序,这将非常乏味且容易出错!不过感谢您的建议!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    相关资源
    最近更新 更多