4

以前は MySQL でスムーズに実行されていた Grails 2.0 アプリケーションを開発します

私たちは管理者から、彼らが好むPostgreSQLに切り替えるように依頼してきました

アプリケーションに多くの新機能を追加しました。その中には、現在問題を引き起こしているものも含まれます: 非同期のサードパーティ Web サービス リクエスト

これで、ドメイン オブジェクトが作成されました。それを Question と呼びましょう。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)

そして、上記のように取得した Id を使用して単純なを実行する (これが恐ろしい「Hibernate Session - Thread」の問題にならないように、executors grails プラグインを介して取得される)を生成するThirdPartyServiceメソッドとしてdoCallAsyncExecutorServiceResource.get(res_id)

問題は、PostgreSQL とpooled = trueではDataSource.groovygetが null を返したり、リソース オブジェクトを返したりすることです。

get(id)a 、 a findById(id)、およびexecuteQueryselect を使用したanの 3 つの異なるリクエストでテストしました。

さらに奇妙なのは、上記の 3 行を同じ方法で使用すると、結果が異なる場合があることです。3つのうち1つだけがnullを返すか、3つがnullを返すか、または何も返さない(これは予想される動作です、思い出します)

Hibernate キャッシュの問題であるかどうかを確認するために PostgreSQL クエリ ログをオンにしましたが、3 つの要求がすべてログに表示されるため、Hibernate はデータベースに毎回ヒットします。正しい ID を持つリソースの挿入、コミット、3 つの選択 (正しいリソース ID が提供されます) が続きます。

このバグがどこから来るかを確認するためにさらにテストする内容について、誰かヒントはありますか? (接続プールを変更しようとしましたが、うまくいきませんでした)

Thread.sleep(1000)最後に、要求の前に a (これは血みどろですが、テストのみを目的としています ;-) )を追加すると、すべてがスムーズに実行されます。したがって、postgres プロセス間の可視性の問題のようですが、それを解決する方法についての手がかりはありません。

4

1 に答える 1

2

あなたは時間をかけてこの問題を研究し、適切に提示された質問として書き上げましたが、重要なログを省きましたか?

保存と非同期取得の間でトランザクションが重複していると推測します。保存がコミットされていないか、保存が行われる前に get が一貫したスナップショットを参照しています。ロギングでプロセスIDが有効になっていることを確認するか、他の方法で接続を区別し、ステートメントがどの順序で発生するかを確認してください。


編集:トランザクションのスナップショットのタイミングのように見えます。

PostgreSQL では、すべてのステートメントがトランザクション内にあります (おそらく暗黙的で持続するステートメントは 1 つだけです)。

デフォルトのモードは「Read Committed」です。これは、トランザクション中に発生したコミットを確認できることを意味します。

「シリアル化可能」レベルのオプションもあります。これは、(ほとんどの場合) トランザクションの開始時にデータベースの凍結されたスナップショットが表示されることを意味します。

詳細については、ドキュメントを参照してください。

2 つの psql コンソールを開き、一方をコミットし、他方を異なる分離レベルで選択するバリエーションをいくつか試してください。ライブ システムで何が起こっているかを確認できるはずです。

于 2012-08-10T15:49:45.917 に答える