使用动态查找器(Hibernate)的Grails StaleObjectException

时间:2014-06-02 22:07:18

标签: hibernate grails staleobjectstate

我有一个批处理作业,它始终在动态查找器上抛出过时的对象异常。理想情况下,我不会为这项工作运行ORM解决方案,但我别无选择。 FormulaTagService中发生异常,它是从FormulaBatchPopulatorService调用的。此应用程序使用一个数据库在两台服务器上运行。一台服务器只执行批处理。

我的问题是: a)为什么一个简单的select语句导致一个域对象实例,在给定的事务期间没有对该对象进行任何更改最终会在会话中持久化,从而导致过时的对象异常? b)是否有可能在transaction.tags上进行排序在事务结束时被持久化,从而导致staleobjectexception如果其他人正在修改不同服务器上的公式?

注意,我确实将服务更改为只读,但我仍然得到过时的对象异常。任何帮助将不胜感激。

公式标签服务

@Cacheable("formulaJob")
      def getFormulaByTeacherTagsOrDefaultBatchJob(Long evaluationTemplateId, List teacherTags) {
          Long formulaByTagsId = existsFormulaWithSameTagsBatchJob(evaluationTemplateId, teacherTags)

          if (DefaultFormulaForEvaluationTemplate.get(evaluationTemplateId) == null && formulaByTagsId ==    
             null) {
               return null;
          }

        Long defaultFormulaId = DefaultFormulaForEvaluationTemplate.get(evaluationTemplateId).formulaId
        return formulaByTagsId ?: defaultFormulaId
    }

    def existsFormulaWithSameTagsBatchJob(Long evaluationTemplateId, List tags){
       // LINE BELOW THROWING STALE OBJECT EXCEPTIONS
        def formulas = Formula.findAllByExtEvaluationTemplateIdAndIsActive(evaluationTemplateId, true)

        for (Formula formula: formulas) {
            def formulaTags = formula.tags
            if (existsTagMatchIgnoringBlankTags(tags, formulaTags)) {
                def id = formula.id
                formula.discard()
                return id
            }
        }
    }

    @CacheEvict(value='formulaJob', allEntries=true)
    def resetTags(){
    }

    def existsTagMatchIgnoringBlankTags(List tagsToCompare, List tagsExisting) {
          if (!tagsToCompare || !tagsExisting) {
              return false
           } 
           else {
               return tagsToCompare?.sort() == tagsExisting?.sort()
            }
    }

FormulaBatchPopulatorService Snippet

   //Doing this below to improve performance of batch processing
         if(index%250==0){
             cleanUpGorm()
             formulaTagService.resetTags()  //cache-evict in formulatagservice
         }

         def cleanUpGorm(){
            def session = sessionFactory.currentSession
            session.flush()
            session.clear()
            propertyInstanceMap.get().clear()
        }

1 个答案:

答案 0 :(得分:1)

我相信你的回答是正确的:

  

b)是否有可能在transaction.tags上进行的排序在事务结束时被持久化,因此如果其他人正在另一台服务器上修改公式,则会导致staleobjectexception?

如果你对标签进行排序并且它是一个列表,我相信Groovy就是这样做的,即对原始列表进行排序并返回它。然后,该列表将在以下时间之一保留:

  1. 交易结束
  2. 请求结束
  3. 下次在当前会话中执行数据库查询(例如findBy将刷新会话)
  4. 它持续存在,因为索引字段可能已更改,因此被GORM / hibernate认为是脏的。

    我有类似的问题,导致同样的问题。我在验证它时看到了其他人是否面对它。

    不确定只读部分发生了什么!您的服务是交易性的吗?