web-dev-qa-db-ja.com

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

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

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

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

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

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

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

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

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

29
Misael P

あなたの問題は、休止状態のセッションが1つのリクエストに対してのみ有効であることです。リクエストの開始時に開き、終了時に閉じます。あなたは答えを推測しました:両方のリクエストが完了する前にHibernateセッションは閉じられます。

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

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

編集:

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

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

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

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

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

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

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

それが役に立てば幸い。

69
nakosspy