hibernate – Grails:选择返回(随机)null,而PostgreSQL中的行存在,并且连接池已打开

我们开发了一个Grails 2.0应用程序,它以前在
MySQL上顺利运行

我们一直要求管理员切换到他们喜欢的PostgreSQL

我们为应用程序添加了一些新功能,包括现在导致我们问题的功能:异步第三方Web服务请求

所以,我们创建了一个域对象,让我们称之为问题.使用afterInsert闭包,将创建一个Resource,以便稍后存储对外部Web服务的调用结果.

class Question implements Serializable {

    static hasMany = [resources: Resource]

    static constraints = {
        resources(nullable: true)
    } 
    def afterInsert() {
        Resource.withNewSession {
            Resource txt = Resource.create(null)
            this.addToResources(txt)
        }
    }           

    Resource retrieveResource(){
      return this.resources.find{ it instanceof Resource }
    }        

    static Question create(Map params) throws SaveDomainException {
        //question creation
    }    
}

我们创建这样的问题:

//first we create question and save it
def question = Question.create(params)
question.save(flush:true, insert:true)
getThirdPartyService().doCallAsync((int)req.retrieveResource().id)

和ThirdPartyService作为方法doCallAsync产生ExecutorService(通过执行程序grails插件获得,这样这不是可怕的“Hibernate Session – Thread”问题)
它执行一个简单的Resource.get(res_id),其ID如上所示获得

问题是,对于PostgreSQL和DataSource.groovy中的pooled = true,get返回有时为null,而不是资源对象.

我们已经测试了3个不同的请求:get(id),findById(id)和带select的executeQuery.

更奇怪的是,在同一方法中上面的三条线,我们有时会得到不同的结果.三个中只有一个返回null,或者三个返回null,或者没有(这是预期的行为,我记得)

我们打开PostgreSQL查询日志来查看它是否是一个Hibernate缓存问题,但是3个请求都出现在日志中,因此每次数据库都会出现hibernate命中.我们看到资源的插入具有正确的id,然后是提交,然后是三个选择(提供正确的资源ID)

有没有人对我们要进一步测试的内容有所暗示,看看这个bug来自哪里? (我们试图改变连接池,没有运气)

最后一件事,如果我们在请求之前添加一个Thread.sleep(1000)(这是血腥但仅用于测试目的;-)),所有操作都会顺利进行.因此,似乎是postgres流程之间可见性的问题,但我们并不知道如何解决这个问题

最佳答案 你花时间研究这个问题并把它写成一个很好的问题,但遗漏了重要的日志?

我推测你的save和async get之间有重叠的事务.在保存发生之前,保存未提交或get正在查看一致的快照.确保在日志记录中启用了进程标识,或者以其他方式区分连接,并查看语句的顺序.

编辑:看起来像事务快照计时.

在PostgreSQL中,所有语句都在一个事务中(可能是隐式的,只持续一个语句).

默认模式为“Read Committed”,这意味着您可以查看事务期间发生的提交.

还有一个“可序列化”级别的选项,这意味着您(大多数)在交易开始时看到数据库的冻结快照.

欲了解更多,请参阅the docs.

打开两个psql控制台,尝试在一个中提交一些变体,在另一个中选择不同的隔离级别.您应该能够看到您的实时系统发生了什么.

点赞