我不确定整个Grails / Hibernate / Tomcat /数据库堆栈中所有邪恶的根源在哪里。我的问题是:我有一个服务(当然是事务性的),用于搜索所谓的(医疗)案例。每个病例都附属于一名患者。
这里是简化的关系(我省略了所有的元数据)。
class Case {
static belongsTo = [casePatient: CasePatient]
}
class CasePatient {
static hasMany = [cases: Case]
}
现在,当保存新案例时,服务首先检查一个案例是否已存在,如果已存在,则只返回。为了保存案例,您显然需要一些案例相关数据和一些与患者相关的数据。如果案例不存在,则服务然后尝试找到患者以防止重复。你可以从标题中猜出我的问题。
无论出于什么恶魔的原因,我碰巧遇到了同一位患者99次(作为一个极端的例子)。用于标识记录的所有字段均为100%匹配。由于搜索而应该是不可能的东西。它并不是一直发生的,很少见,但它发生了,它很糟糕。一旦有多名患者从搜索中返回,该服务就像一个小孩一样大声呼喊,然后抛出异常。毕竟只能有。
奇怪的是:数据库上的时间戳表明这些记录已经相隔30秒创建,导致这个混乱发生的总时间跨度为50分钟。看起来50分钟交易还没有持续到数据库,否则我没有解释为什么搜索找不到任何东西。
Web服务由我们自己的软件使用,该软件尝试上传数据。它自己执行搜索,只有在找不到任何内容的情况下,才会创建对新案例的请求。
不幸的是我没有调试日志,所以我无法看到服务器上发生了什么。我设置了一个测试装置以获得一些,但由于我不知道如何挑起它...我所能做的就是等待并希望它会在某个时刻发生。< / p>
无论如何,我不知所措。我不知道从哪里开始寻找。从服务代码来看,我(以及同事)似乎不可能发生这种情况。你们有没有关于如何钉下这个吸盘的建议?
使用的软件:
答案 0 :(得分:0)
这是数据库。对于一些尚未知的原因,数据库中某处存在争用,导致我的病例和患者的INSERT语句及时通过。 Grails服务等待语句完成,但创建案例的客户端超时后,您有三个猜测,前两个不计数,30秒。之后,它只是继续下一个文件(基于文件触发操作),再次做同样的事情,很可能是同一个病人。
当第一个INSERT事务仍在等待处理时,第二个请求无法找到该数据并决定创建一个新案例和一个新病人本身,最终将另一个INSERT添加到队列中。在这种极端情况下,这发生在50秒的一个时间段内,导致99个保存案例请求在数据库结已破裂时全部被刷新。
我通过人工创建一个允许阅读而不是写作的共享锁来验证这一论点。这意味着所有的SELECT工作正常,并没有找到任何东西。只有在INSERT数据发生时,锁才会阻止执行。我等了几分钟才发布了锁,然后我发现自己有重复的条目,那里不应该是。
虽然我仍然需要弄清楚这个锁来自何处,但我通过在服务方法开始时为该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()
}
session
来自sessionFactory.currentSession
。
现在数据库在15秒后取消请求,整个保存请求被中止。