2

次のコードを実行すると、「スレッド "main" org.hibernate.LazyInitializationException の例外: プロキシを初期化できませんでした - 所有しているセッションが閉じられました」というエラーが発生し続けます。

public ArrayList<ProfileDTO> getInitialProfiles(Contracts ct){ 
   SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
   Session session=sessionFactory.openSession();
   Transaction tx=session.beginTransaction(); 
   ArrayList<ProfileDTO> profileDTOs=new ArrayList<ProfileDTO>();
   try{
       Hibernate.initialize(ct);
        SQLQuery query=session.createSQLQuery("select {b.*},{p.*},{t.*} from bidtool.bt_boiler_plates b,bidtool.bt_profile p,bidtool.bt_trade_lane t where b.contract_id=:val AND p.contract_id=:val AND t.contract_id=:val")
                  .addEntity("b",Boiler_Plates.class)
                  .addEntity("p",BidToolProfiles.class)
                  .addEntity("t",BidToolTradeLanes.class);
        query.setParameter("val", ct.getContract_id());
        List list=query.list();  

        Iterator iteContract = list.iterator();
        while ( iteContract.hasNext() ) {
            Object[] pair =(Object[]) iteContract.next();
            Boiler_Plates bp=(Boiler_Plates)pair[0];
            BidToolProfiles p=(BidToolProfiles)pair[1];
            ProfileDTO profileDTO=new ProfileDTO();
            profileDTO.setProfileId(p.getProfileId());
            profileDTO.setBt_contracts(p.getBt_contracts());
            profileDTO.setCreated(p.getCreated());
            profileDTO.setProfileContent(p.getProfileContent());
            profileDTO.setEditable(p.getEditable());
            profileDTO.setProfileName(p.getProfileName());
            profileDTOs.add(profileDTO);
        } 
        return profileDTOs;
   }
   catch(Exception ex){
       System.out.println(ex.getMessage());
       return profileDTOs;
   }
   finally{
    session.flush();   
    session.close();
   }
 }

セッションを閉じない限り問題なく動作しますが、それはできません。セッションを閉じる必要があります。あなたの助けに感謝します。ありがとうございました。

4

4 に答える 4

6

セッションが閉じられた後、休止状態のエンティティの関連付けまたはコレクションにアクセスすると、エラーが発生します。あなたのコードを見ると、問題はおそらく次の行にあると思います。

profileDTO.setBt_contracts(p.getBt_contracts());

別のセッション内から、コード内の別の場所でこのコレクションにアクセスしようとすると。

クエリを次のように変更してみてください。

select {b.*},{p.*},{t.*} from bidtool.bt_boiler_plates b,bidtool.bt_profile p,bidtool.bt_trade_lane t left join fetch p.bt_contracts btcontracts where b.contract_id=:val AND p.contract_id=:val AND t.contract_id=:val

コレクションに結合フェッチを追加したことに注意してください。BidToolProfilesこれにより、エンティティがフェッチされると同時に契約コレクションがフェッチされるようになります。また、コレクションを DTO に設定する前に、コレクションを初期化してみてください。

Hibernate.initialize(p.getBt_contracts());
profileDTO.setBt_contracts(p.getBt_contracts());
于 2012-05-30T16:48:02.707 に答える
3

セッションが閉じられたら、使用する予定のすべてのオブジェクトを初期化する必要があります。

アドレスとの OneToOne 遅延関連付けを持つ User エンティティがあるとします。また、セッションが開いている間にユーザーをロードするとします。住所は遅延ロードされるため、最初に住所に対してメソッドを呼び出すと (user.getAddress().getStreet()たとえば)、Hibernate はクエリを実行してユーザーの住所をロードし、その通りにアクセスできるようにします。しかし、セッションが閉じられると、データベースへの接続がなくなり、User エンティティが切り離されるため、Hibernate はこの例外をスローします。

必要なオブジェクトを初期化するために使用Hibernate.initialize()するか、必要なすべてを一度にロードするために必要なフェッチを持つクエリを実行します。

補足: あなたの例外処理はひどいものです。プロファイルを返すように求められた場合、「申し訳ありませんが、次の例外のためにそれを行うことができませんでした」と言う代わりに、基本的に例外を無視して「データベースにプロファイルがありません」と言います。がん検出システムがこのように機能することを想像してみてください。システムに例外があったため、がんが検出されないようにしたいですか?

于 2012-05-30T16:49:25.070 に答える
0

session.merge()古いセッションからロードされたインスタンスを新しいセッションとマージするために使用します。ちなみにこれは、Hibernate がデータベースからエンティティを再度ロードすることを意味します。

もう 1 つの可能性は、遅延読み込みを回避することです。セッションがまだ開いている限り (その時点で値が必要ない場合でも)、マッピングまたは必要な値にアクセスします。

于 2012-05-30T16:48:12.217 に答える
0

その方法をどのように使用していますか?あなたのマッピングはどのようなものですか?遅延読み込みを有効にしているプロパティは何ですか? これはウェブアプリですか?ProfileDTO を作成していますが、getBt_contracts はどうでしょうか。これにより、「セッション対応」の BidToolProfiles からものが返されるため、そのメソッドが返された後に遅延ロードされたプロパティにアクセスすると、このエラーが発生します。

これは、マッピングが表示されないことを考えると、間違っていると思われる例にすぎません。ここで重要なことは、必要なタスクを実行するために必要なすべてのプロパティを遅延ロードした後、セッションを閉じる必要があるということです。

繰り返しになりますが、これが Web アプリであるかどうかに応じて、さまざまなセッション m 管理戦略を使用できます (Web アプリでは要求ごとのセッション、デスクトップ アプリの場合はスレッドごとのセッションなど)。

于 2012-05-30T16:45:20.533 に答える