4

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

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

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

所以,我们创建了一个域对象,我们称之为问题。使用afterInsert闭包Resource创建 a,以便稍后存储对外部 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(通过 executors grails 插件获得,因此这不是可怕的“Hibernate Session - Thread”问题),它Resource.get(res_id)使用如上所示获得的 Id执行一个简单的

问题在于,使用 PostgreSQL 和pooled = trueinDataSource.groovy时,get有时返回 null,有时返回资源对象。

我们测试了 3 个不同的请求: a get(id)、 afindById(id)executeQuery带有 select 的 an。

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

我们打开了PostgreSQL查询日志看看是不是Hibernate缓存问题,但是这3个请求都出现在了日志中,所以hibernate每次都命中数据库。我们看到插入了具有正确 ID 的资源,然后是提交,然后是三个选择(提供了正确的资源 ID)

有没有人暗示我们将进一步测试以查看此错误来自何处?(我们试图改变连接池,没有运气)

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

4

1 回答 1

2

您已经花时间研究这个问题并将其写成一个很好的问题,但忽略了重要的日志?

我推测您的保存和异步获取之间存在重叠事务。保存未提交或获取在保存发生之前看到一致的快照。确保您在日志记录中启用了 process-id,或者以其他方式来区分连接并查看语句发生的顺序。


编辑:看起来像事务快照时间。

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

默认模式是“Read Committed”,这意味着您可以看到在事务期间发生的提交。

还有一个“可序列化”级别的选项,这意味着您(大部分)在事务开始时会看到数据库的冻结快照。

有关更多信息,请参阅文档

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

于 2012-08-10T15:49:45.917 回答