在同步方法中使用Grails重复记录

时间:2013-01-03 02:45:07

标签: hibernate session grails synchronization findby

我花了整整一个晚上试着想出来,我在这一点上绝望。 我的Grails 2.1.0项目中有服务类。它对Web服务执行查询 - 查询是线程化的。一旦线程获得了数据,它就会调用synchronized方法WriteToDB,而方法String field会取一个名称(findByName)并通过flush:true检查域名。如果存在记录,则不执行任何其他操作来创建新记录。

现在我检查了,方法确实只允许调用一个线程,这里是log sample:

  

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

     

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

     

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

     

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

     

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

     

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

     

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

     

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

     

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

     

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

然而,我得到了重复的记录!每次我保存新记录时,我都会 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 } } } 。我不明白为什么会一直这样?我手动测试 - 在测试之前向DB添加了一条已知记录,它从未重复,但是,正在保存的新记录最多可以复制6次。

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

[2013年2月1日更新]

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

{{1}}

错误示例:

  

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

     

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

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

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

2 个答案:

答案 0 :(得分:3)

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

Domain.save(flush:true) - 由于线程无效。

以下是我创建线程的示例:

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

修复程序在此处找到:Grails, GPars and data persistence

我将Domain.withTransaction替换为Domain.withNewSession

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

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

谢谢吴金钊,你的建议很有帮助!

答案 1 :(得分:2)

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

static constraints = {
    name unique: true
}

到您的域类,然后在服务方法中捕获相关的异常,而不是使用findByName检查有效性。

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