2012-04-05 99 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