31

次のようなエラーが発生しました。

プロキシを初期化できませんでした - セッションがありません

私はJava、休止状態、および春を扱っています。このエラーは、PDF ドキュメントを生成しようとすると発生します。次の手順に従って、その場で生成してデータベースに保存しています。

  1. POST メソッドでアプリにリクエストを送信しました。これにより、オンザフライで PDF が生成され、ユーザーに表示されます。

  2. そのリクエストの直後に別のリクエストを送信しますが、ajax を介してリクエストを送信します。これにより、同じ PDF が生成されますが、DB に保存されます。

このエラーは、「プロキシを初期化できませんでした - セッションがありません」というエラーが原因で、クエリを実行できなかったことを示しています。

同じユーザー セッションから同じメソッドを 2 回呼び出して、間違っていることはありますか? 両方のリクエストが完了する前にセッションが閉じられた可能性はありますか?

誰かが何が起こっているのかを理解するのを手伝ってくれることを願っています.

4

1 に答える 1

76

あなたの問題は、休止状態のセッションが 1 つの要求に対してのみ存続することです。リクエストの開始時に開き、最後に閉じます。ご想像のとおり、両方のリクエストが完了する前に Hibernate セッションが閉じられました。

正確に何が起こっているのですか?両方のリクエストの間、エンティティ オブジェクトは存続します。どのように?それらは HTTP セッション (セッションと呼ばれる別のもの) に保存されます。使用しているフレームワークについてあまり情報を提供していないため、詳細を説明することはできませんが、使用しているフレームワークが何らかの形でエンティティを HTTP セッションに保持します。このように、フレームワークにより、複数のリクエストに対して同じオブジェクトを簡単に操作できるようになります。

2 番目のリクエストの処理が開始されると、コードは hibernate によって遅延初期化されたエンティティ (通常はコレクションの要素) にアクセスしようとします。エンティティは休止状態のセッションにアタッチされていないため、休止状態はそれを読み取る前に休止状態のプロキシを初期化できません。セッションを開き、ajax リクエスト処理の開始時にエンティティをセッションに再アタッチする必要があります。

編集:

舞台裏で何が起こっているのかを簡単に説明しようと思います。すべての Java Web フレームワークには、要求を処理する 1 つ以上のサーブレットがあります。サーブレットは、最終的に応答 (HttpResponse) を生成する新しいスレッドを作成することによって、各要求 (HttpRequest) を処理します。各リクエストを処理するメソッドは、このスレッド内で実行されます。

リクエスト処理の開始時に、アプリケーションは処理に必要なリソース (トランザクション、Hibernate セッションなど) を割り当てる必要があります。処理サイクルの終わりに、これらのリソースが解放されます (トランザクションがコミットされ、休止状態セッションが閉じられ、JDBC 接続が解放されるなど)。これらのリソースのライフサイクルは、フレームワークによって管理することも、コードによって行うこともできます。

HTTP などのステートレス プロトコルでアプリケーションの状態をサポートするために、HttpSession オブジェクトがあります。私たち (またはフレームワーク) は、同じクライアントの異なる要求サイクル間で関連性のある情報を HttpSession に置きます。

最初のリクエストの処理中に、hibernate はデータベースからエンティティを (遅延して) 読み取ります。遅延初期化のため、このオブジェクトの構造の一部は休止状態のプロキシ オブジェクトです。これらのオブジェクトは、それらを作成した休止状態のセッションに関連付けられています。

2 番目の要求を処理しようとすると、フレームワークは HttpSession オブジェクト内の前の要求からエンティティを見つけます。次に、遅延初期化され、現在は休止状態のプロキシ オブジェクトである子エンティティからプロパティにアクセスしようとしています。ハイバネート プロキシ オブジェクトは、誰かがそのプロパティの 1 つにアクセスしようとしたときに、ハイバネート セッションにデータベースからの情報を入力するように要求する実際のオブジェクトの模倣です。これは、休止状態のプロキシがやろうとしていることです。しかし、そのセッションは前のリクエスト処理の最後に閉じられたため、ハイドレートする (実際の情報で満たされる) ために使用する休止状態のセッションがありません。

2 番目の要求の開始時に休止状態セッションを既に開いている可能性がありますが、このエンティティは別の休止状態セッションによって読み取られたため、プロキシ オブジェクトを含むエンティティを認識していないことに注意してください。エンティティを新しい休止状態セッションに再接続する必要があります。

デタッチされたエンティティを再アタッチする方法については多くの議論がありますが、現時点で最も簡単な方法は ですsession.update(entity)

それが役に立てば幸い。

于 2013-05-25T19:12:41.100 に答える