2012-04-05 6 views
4

私は、HibernateとJSF/primefacesを使ってJava Webアプリケーションを開発しています。 Hibernate、session、lazyloading

のようなエラーが発生することがあります。1)同じ識別子を持つオブジェクトが既にセッションに関連付けられています。

2)遅延初期化のロードに失敗しました*、セッションが存在しない、またはセッションがすでに閉じられています。

これは私のアプリで不適切なコーディングが原因であることがわかりました。 これはaapを実行している方法です。

ユーザーがページを要求したとき(従業員のリストにする)。 ユーザーは従業員リストページ(empployeeList.xhtml)を取得します EmployeeListMBeanはこのページの管理対象Beanです。コンストラクタ内のマネージドBean内の は、メソッドpopulateEmployees()を呼び出しています。 populateEmployee()は、EmployeeDaoメソッドgetAllEmployee()を使用してgetAllemployeesを使用します。

Employeeクラスは、ここに行く:メソッドで私がセッションを終了し、その結果をバック返しています、ここ

public class EmployeeDao implements Serializable{ 
    private SessionFactory factory; 
    private Session session; 
    public void addEmployee(Employee employee){ 
     factory = HibernateUtil.getSessionFactory(); 
     session = factory.openSession(); 
     session.beginTransaction(); 
     session.save(employee); 
     session.getTransaction.commit();   
    } 
    public List<Employee> getAllEmployee(){ 
     factory = HibernateUtil.getSessionFactory(); 
     session = factory.openSession(); 
     session.beginTransaction(); 
     List<Employee> cities = session.getNamedQuery("Employee.getAllEmployee").list(); 
     session.close(); 
     return cities; 
    } 

    public Employee getEmployeeByEmployeeId(long employeeId){ 
     factory = HibernateUtil.getSessionFactory(); 
     session = factory.openSession(); 
     session.beginTransaction(); 
     Employee employee = (Employee) session.get(Employee.class, employeeId); 
     session.close(); 
     return employee; 
    }  
} 

質問1) :ここ

@Entity 
@Table(name = "Employee") 
@NamedQueries({ 
    @NamedQuery(name = "Employee.getAllEmployee", query = "from Employee"), 
    @NamedQuery(name = "Employee.findEmployeeByFirstName", query = "from Employee where firstName = :firstName"), 
    @NamedQuery(name = "Employee.findEmployeeByLastName", query = "from Employee where lastName = :lastName"), 
    @NamedQuery(name = "Employee.findEmployeeByMiddleName", query = "from Employee where middleName = :middleName"), 
    @NamedQuery(name = "Employee.findEmployeeByOffice", query = "from Employee where office.id = :officeId") 
}) 
public class Employee implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "EID") 
    private long id; 
    @Column(name = "FIRST_NAME") 
    private String firstName; 
    @Column(name = "LAST_NAME") 
    private String lastName; 
    @Column(name = "GENDER") 
    private String gender; 
    @Column(name = "DOB") 
    @Temporal(javax.persistence.TemporalType.DATE) 
    private Date dateOfBirth; 
    @Column(name = "DOH") 
    @Temporal(javax.persistence.TemporalType.DATE) 
    private Date dateOfHire; 
    @ManyToOne(cascade= CascadeType.ALL) 
    private Office office; 
    @OneToOne(cascade = CascadeType.ALL) 
    private ResidenceAddress residence; 
    @OneToMany 
    private List<Project> projects; 

    //getters and setters 

} 

は私EmployeeDaoですto managedbeans。 従業員のリストページでは、テーブルのリストの名前はdobのdateOfHireです。私はより詳細なボタンビューを持っています。このボタンをクリックすると、同じmanagedbeansを使用して作業している選択した従業員のすべてのプロジェクトを表示したいのですが、エラー(2)、lazyloadに失敗、セッションまたはセッションが閉じられていません。 セッションをdaoのgetemployeeMethodで開いたままにしておくと、メモリリークの問題やその他の問題が発生する可能性があります。そうですか? また、私は怠惰で熱心な読み込みを試みました。これらのタイプのフェッチをいつどのように使うべきか、私に明確なアイデアを与えてください。 どうすればこの問題を解決できますか?私はこれを解決するためのフィルターやfacististersに行くことができますか?

質問2) 従業員のプロジェクトを編集しようとしていて、session.saveorupadte()、merge()、flush()を使用して更新しようとすると、このようなエラーが発生します。既にセッションに関連付けられています " どうすればこの問題を解決できますか?

質問3) 私はsessionfactoryがリソースを消費していることを知っています。 1つのアプリケーションには1つのインスタンスで十分です。セッションについてはどうですか?アプリのシングルユーザーの場合は 、セッションは1回だけ必要ですか? このようなアプリを開発するための良い戦略を教えてください。あなたのすべてに感謝:)

+0

これは実際には複数の質問です。 1つの質問につき1つの問題に集中すれば、より良い回答を得ることができます。 –

答えて

0

もう1つの答えで述べたように、開始したトランザクションはcommitingである必要があります。データを読み取っている間、取引は必要ありません。

質問1:レイジーローディング。

それはあなたのビューで自由に使用することができるようにあなたは、lazy loadprojectsする必要があります。これを行うには、以下のようにコードを変更し、

@OneToMany(fetch=FetchType.LAZY) 
private List<Project> projects; 

質問2:同じ識別子を持つオブジェクトが既に存在しています。

デバッグし、保存するオブジェクトのidをデバッグして調べます。私はあなたのエラーのスタックトレースなしでここで多くの助けができません。

質問3:セッションとセッションファクトリー。

ここからは、この2つの違いはarticleです。

のSessionFactoryは、1つのデータストアの休止状態の概念であり、多くのスレッドが同時にそれにアクセスし、セッションや単一のデータベースに対するコンパイルされたマッピングの不変のキャッシュを要求できるように、スレッドセーフです。 SessionFactoryは通常、起動時に一度しか構築されません。 SessionFactoryは、アプリケーションコードで簡単にアクセスできるように、何らかのシングルトンでラップする必要があります。

セッションは軽量で、スレッドセーフではないオブジェクト(スレッド間では共有できません)で、データベースとの単一作業単位を表します。セッションはSessionFactoryによって開かれ、すべての作業が完了すると閉じられます。 Sessionは、永続性サービスの主要インタフェースです。セッションは、遅延接続(必要な場合のみ)を遅延接続します。あまりにも多くのセッションを作成しないようにするには、currentSession()メソッドを何回呼び出しても、現在のセッションを取得するために、以下のようにThreadLocalクラスを使用できます。

だから、あなたのコードでは、あなたはsessionのローカル変数を作成し、それをあなたがメソッドを閉じるたびに閉じる必要があります。

0

私はあなたの最初の質問の答えはあなたがすべての利用状況でセッションをコミットしないと思います。私はあなたのトランザクションをコミットしないgetAllEmployeeメソッドとgetEmployeeByEmployeeIdメソッドを意味します。あなたは追加できますsession.getTransaction.commit();私はわかりませんが、最初の問題はトランザクションがコミットしないために2番目の問題を引き起こす可能性があります。セッションの良い戦略については、thisをご覧ください。

+0

さて、私はコミットintホースメソッドを追加することでそれを試みます。しかし、私たちがデータベースからオブジェクトを読み込んでいて、データベースに反映させるために何も変更しないのであれば、コミットを含める理由はわかりません。addEmployeeメソッドでは、コミットしました。私は正しいのではない、私はコミット()の私の理解を意味するか? – amFroz

+0

私の理解では、コミットは単にデータベーストランザクションを終了します。 'データベーストランザクションをコミットすると、セッションがJDBC接続から切断され、接続がプールに返されます。記事全体を読むことができますhttp://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html – mbaydar

+0

よろしくお願いします。ありがとう。私はそれを試みます。セッションを開く際に問題があり、すべてが表示されていますか?私のアプリケーションでは、私はmanagedbeansで、セッションを開くことができますか?いいえ、私はそれが同じ識別子問題(質問2)を持つオブジェクトの私の問題を解決できると思います。 – amFroz