我花了整整一个晚上试着想出来,我在这一点上绝望。
我的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修改此代码...想法?
答案 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
检查有效性。
或者您可能需要从服务方法发布一些代码以找出重复的原因。