Grails 事务:不应该有任何重复数据



我不确定整个Grails/Hibernate/Tomcat/Database堆栈中所有邪恶的根源在哪里。我的问题是:我有一个服务(当然是事务性的),用于搜索所谓的(医疗)案例。每个病例只对应一个患者。

这是简化的关系(我省略了所有的元数据)。

class Case {
    static belongsTo = [casePatient: CasePatient]
}
class CasePatient {
    static hasMany = [cases: Case]
}

现在,当保存一个新案例时,服务首先检查是否已经存在,如果存在,则返回。为了保存一个病例,你显然需要一些与病例相关的数据和一些与患者相关的数据。如果该病例不存在,则服务将尝试找到该患者,以防止重复。从标题你大概可以猜到我的问题了。

不管出于什么邪恶的原因,我碰巧遇到同一个病人99次(作为一个极端的例子)。所有用于标识记录的字段都100%匹配。由于搜索,这应该是不可能的。这种情况不会一直发生,很罕见,但它确实发生了,而且很糟糕。一旦有不止一个病人从搜索中返回,服务就会被设计成像小孩一样大声喊叫,除了例外情况外,它还会到处乱扔。毕竟只能有一个

奇怪的是:数据库上的时间戳表明这些记录是间隔30秒创建的,这导致发生这种混乱的总时间跨度为50分钟。看起来好像有50分钟的事务没有被持久化到数据库中,否则我无法解释为什么搜索找不到任何东西。

webservice是我们自己的软件用来上传数据的。它自己执行搜索,只有在没有找到的情况下,才创建一个新案例的请求。

不幸的是,我没有调试日志,所以我无法看到服务器上发生了什么。我已经设置了一个测试安装来获得一些,但是因为我真的不知道如何激发它……我所能做的就是等待,希望它会在某个时候发生。

不管怎样,我有点茫然。我不知道该从哪开始找。从服务代码来看,我(和一位同事)似乎不可能发生这种情况。你们有什么建议能让我搞定这家伙吗?软件使用:

  • Grails 2.4.4(和2.5.0)
  • Tomcat 7
  • OpenJDK Runtime Environment (IcedTea 2.5.5) (7u79-2.5.5-1~deb7u1)
  • PostgreSQL 9.3
  • Debian 7.8 (wheezy)

是数据库。由于某种未知的原因,数据库中的某个地方出现了争用,导致我的病例和患者的INSERT语句无法及时执行。Grails服务等待语句完成,但是创建case的客户机在30秒后超时,您猜了三次,前两次不算数。之后,它只是继续处理下一个文件(操作以文件为基础触发),再次执行相同的操作,并且很可能针对同一患者。

当第一个INSERT事务仍在等待处理时,第二个请求将找不到该数据,并决定自己创建一个新病例和一个新患者,最终向队列中添加另一个INSERT。在这个极端的情况下,这种情况发生在50秒的时间跨度内,一旦数据库上的结爆发,就会刷新99个save-case请求。

我通过人为地在病人表上创建一个共享锁来验证这个论点,该锁允许读但不允许写。这意味着所有的select都工作得很好,没有找到任何东西。只有当涉及到INSERT数据时,锁才会阻塞执行。我等了几分钟才释放锁,然后我发现自己有重复的条目,不应该有任何。

虽然我仍然需要弄清楚这个锁来自哪里,但我通过在service方法的开始为save-session设置语句超时来解决这个问题。我有一个实用的方法。

static void setStatementTimeout(def session, int milliseconds) {
    log.trace "->setStatementTimeout: <milliseconds: $milliseconds>"
    def query = session.createSQLQuery("set statement_timeout to $milliseconds")
    query.executeUpdate()
}

sessionsessionFactory.currentSession得到。

现在数据库在15秒后取消请求,整个保存请求被中止。

最新更新