2012-04-05 144 views
4

我正在開發一個使用Hibernate和JSF/primefaces的Java Web應用程序。 我有時得到錯誤等休眠,會話,延遲加載

1)與相同標識符的對象已經與會話相關聯。

2)未能加載延遲初始化*,沒有會話存在或者會話已經關閉。

我知道這是由於我的應用程序編碼不正確。 這是我在做的一個方法:

當用戶請求一個頁面(讓它成爲員工列表)。 用戶將獲得員工列表頁面(empployeeList.xhtml) EmployeeListMBean是此頁面的託管bean。 在構造函數的託管bean中調用方法populateEmployees()。 populateEmployee()將使用EmployeeDao方法getAllEmployee()來getAllemployees。

Employee類放在這裏:

@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:

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) 這裏,在這些方法中我將結束會話,然後返回回結果到managedbeans。 所以在員工列表頁面列表中列出了名字dob dateOfHire。我有一個buutton查看更多細節。在點擊這個按鈕時,我想顯示選定的員工使用相同的managedbeans的所有項目,但它給我錯誤(2),lazyload失敗,沒有會話或會話已經關閉。 如果我保持在dao的getemployeeMethod中打開會話,我猜可能會導致內存泄漏問題或其他問題。是這樣嗎? 也,我嘗試了懶惰和渴望加載。請告訴我何時/如何使用這些類型的抓取。 我該如何解決這個問題?我可以去過濾器或facelisteners解決這個問題嗎?

問題2) 如果試圖編輯僱員的項目,並使用session.saveorupadte(),merge(),flush()更新,我得到這樣的錯誤,「具有相同標識符的對象是已經與會話相關「 我該如何解決這個問題?

問題3) 我知道這個SessionFactory是比較消耗資源。所以只有一個實例就足夠用於一個應用程序。但會話呢? 對於單用戶的應用程序,只需要一個會話? 請告訴我開發這樣的應用程序的好策略。

感謝大家:)

+0

這確實是多個問題。如果您專注於每個問題的一個問題,您可能會得到更好的答覆。 – 2012-04-08 12:26:32

回答

0

至於說在其他的答案,你應該commiting你已經開始了交易。您在閱讀數據時不需要交易。

問題1:延遲加載。

您需要lazy loadprojects,以便它可以在您的視圖中自由使用。爲了做到這一點,修改爲下面的代碼,

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

問題2:用相同標識符的對象是已經存在。

調試並找出您要保存的對象的id。如果沒有堆棧跟蹤錯誤,我無法幫助您。

問題3:session和sessionfactory。

下面是這兩個從這個article之間的差異。

SessionFactory的是一個單一的數據存儲的Hibernate的概念,是線程安全的,這樣多線程可以同時並要求訪問會話以及單個數據庫映射關係經過編譯的不可變的緩存。 SessionFactory通常只在啓動時創建一次。 SessionFactory應該用某種單例包裝,以便在應用程序代碼中輕鬆訪問它。

會話是一個輕量級和非線程安全的對象(不能在線程之間共享),它表示與數據庫的單個工作單元。會話由SessionFactory打開,然後在所有工作完成時關閉。會話是持久性服務的主要接口。會話會延遲地獲得數據庫連接(即僅在需要時)。爲避免創建太多會話,無論您調用currentSession()方法多少次,都可以使用ThreadLocal類來獲取當前會話。

因此,在您的代碼中,您應該爲session創建一個局部變量,並在每次關閉該方法時關閉它。

0

我覺得你的第一個問題的答案是你沒有在每次使用提交您的會話。我的意思是在getAllEmployee和getEmployeeByEmployeeId方法中,您不會提交事務。您可以添加session.getTransaction.commit();我不確定,但您的第一個問題可能會導致第二個問題,因爲事務沒有提交。對於良好的策略與會議,你可以看看this

+0

好吧,我會嘗試通過添加一個提交int int軟管方法。但是,我不確定爲什麼要包含提交,如果我們只是從數據庫中讀取對象,並且不做任何更改以反映在數據庫中。在addEmployee方法中,我已經提交了,因此存在寫入操作。我是不是對,我的意思是我對commit()的理解? – amFroz 2012-04-09 05:28:33

+0

在我的理解中,提交只是簡單地結束數據庫事務。 '提交數據庫事務會將會話從JDBC連接斷開並將連接返回到池。'你可以在這裏閱讀完整的文章http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/transactions.html – mbaydar 2012-04-09 05:44:58

+0

好吧。謝謝。我會嘗試。在開幕式和所有視圖中是否有問題?我的意思是在我的應用程序中,我可以在managedbeans中打開會話嗎?如果不是的話,我認爲它可以解決我的標識符問題相同的問題(問題2)。 – amFroz 2012-04-09 06:36:42