1

我花了整个晚上试图弄清楚,此时我很绝望。我的 Grails 2.1.0 项目中有服务类。它对 Web 服务执行查询 - 查询是线程化的。一旦线程获得了数据,它就会调用synchronized方法WriteToDB,该方法又接受一个名称 ( String field) 并通过findByName. 如果记录存在,则不执行任何其他操作来创建新记录。

现在我检查了方法确实只允许一次调用一个线程,这里是日志示例:

错误 2013-01-02 21:29:47,408 [Thread-21] 错误 - WriteToDB START

错误 2013-01-02 21:29:47,474 [Thread-21] 错误 - WriteToDB 已完成

错误 2013-01-02 21:29:47,475 [Thread-20] 错误 - WriteToDB START

错误 2013-01-02 21:29:47,571 [Thread-20] 错误 - WriteToDB 已完成

错误 2013-01-02 21:29:47,581 [Thread-49] 错误 - WriteToDB START

错误 2013-01-02 21:29:47,866 [Thread-49] 错误 - WriteToDB 已完成

错误 2013-01-02 21:29:47,867 [Thread-45] 错误 - WriteToDB START

错误 2013-01-02 21:29:48,202 [Thread-45] 错误 - WriteToDB 已完成

错误 2013-01-02 21:29:48,203 [Thread-48] 错误 - WriteToDB START

错误 2013-01-02 21:29:48,320 [Thread-48] 错误 - WriteToDB 已完成

但是,我得到重复的记录!!!每次我保存新记录时,我都会这样做flush:true。我不明白为什么它一直在发生?我手动测试 - 在测试之前将一条已知记录添加到数据库中,并且它从未被复制,但是,正在保存的新记录最多被复制 6 次。

请帮忙。我需要索引一些东西吗?或者以特殊的方式冲洗一些东西?为什么会这样?

[2013 年 2 月 1 日更新]

这是我用来保存记录的代码:

      if(!f) { // Check if record doesn't exist then save, else nothing
          f = new Feature(name: featureName)
          if( !f.save(flush: true) ) {
              f.errors.each {
                  log.error it
              }
          }
      }

还有错误示例:

错误 2013-01-02 22:25:58,868 [Thread-20] 错误 util.JDBCExceptionReporter - 键“名称”的重复条目“自动传输”

错误 2013-01-02 22:25:58,873 [Thread-20] 错误 hibernate.AssertionFailure - 发生断言失败(这可能表明 Hibernate 中存在错误,但更有可能是由于会话使用不安全)消息:空 id在 Project2.Feature 条目中(发生异常后不要刷新 Session)

我可以这样解释(我在“保存”部分代码之前得到了 FindByName):我查找记录但它不存在所以我正在创建它,现在它抱怨重复条目,我得到变量“f”的空值后来我将其作为关系插入到另一个表中。

我想我可能会尝试使用 try catch 块修复此代码......想法?

4

2 回答 2

3

好的,经过一些测试和研究,我发现了一个问题。

Domain.save(flush:true)- 由于线程而没有工作。

这是我的线程创建示例:

Thread.start {
    Domain.withTransaction {
         // Doing stuff and calling synchronization method to write data to DB
    }
}

在这里找到了修复:Grails、GPars 和数据持久性

我替换Domain.withTransactionDomain.withNewSession

Thread.start {
    Domain.withNewSession {
         // Doing stuff and calling synchronization method to write data to DB
    }
}

save(flush: true)开始写入 mySQL。由于数据被写入 mySQL,findBy... 开始返回正确的结果,因此我的应用程序不再尝试创建重复记录。问题解决了!

谢谢你,金兆武,你的建议很有帮助!

于 2013-01-06T05:52:30.697 回答
2

这是一个简单的解决方案:只需添加

static constraints = {
    name unique: true
}

到您的域类,然后在服务方法中捕获相关异常,而不是使用findByName.

或者您可能需要从您的服务方法中发布一些代码以找出重复的原因。

于 2013-01-03T03:02:15.840 回答