Hibernate中,会话,惰性加载(Hibernate, session, lazyloading

2019-09-16 09:01发布

我正在开发使用Hibernate和JSF / primefaces Java Web应用程序。 我有时会收到类似的错误

1)具有相同标识符的对象已经与会话相关联。

2)未能加载延迟初始化*,无会话中或会话已经关闭。

我知道这是因为我的应用程序不正确的编码。 这是我做AAP方式:

当用户对页面请求(让它成为员工的列表)。 用户将得到员工列表页面(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(),合并(),同花顺(),我得到这样的错误“与相同标识符的对象已与会话相关联”我该如何解决这个问题?

问题3)我知道这个SessionFactory是比较消耗资源。 因此,只有单一实例是足以让一个应用程序。 但是关于会议什么? 对于应用程序的单一用户,只需要一个会话? 请告诉我要开发这样的应用程序很好的策略。

感谢大家:)

Answer 1:

正如在其他的答案告诉,你应该commiting你已经开始了交易。 当你正在阅读的数据不需要交易。

问题1:延迟加载。

您需要延迟加载 projects ,以便它可以自由地在您的视图中使用。 要做到这一点,修改如下代码,

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

问题2:用相同标识符的对象是已经存在。

调试,并找出哪些是id你要保存的对象。 我也没有太大的帮助这里没有你的错误的堆栈跟踪。

问题3:会话和SessionFactory的。

下面是这两者之间的差别的文章 。

SessionFactory的是一个单一的数据存储的Hibernate的概念,是线程安全的,这样多线程可以同时并要求访问会话以及单个数据库映射关系经过编译的不可变的缓存。 一个SessionFactory通常只在启动时建立一次。 SessionFactory的应该被包裹在某种单身的,这样它可以在应用程序代码很容易地访问。

会话是一种重量轻和表示与所述数据库中的单个单元的工作的非线程对象(否,则不能线程之间共用)。 会议是由一个SessionFactory打开,然后在所有工作完成后关闭。 Session是持久性服务的主要接口。 会话懒惰地获得数据库连接(即仅当需要时)。 为了避免产生如下图所示,以获取当前会话无论你有多少次拨打电话到currentSession()方法的ThreadLocal类可用于会话太多。

所以,在你的代码,你应该创建一个局部变量session ,并在每次关闭的方法时将其关闭。



Answer 2:

我想你的第一个问题的答案是你没有在每次使用提交您的会话。 我的意思是在getAllEmployee和getEmployeeByEmployeeId方法你不提交您的交易。 您可以添加session.getTransaction.commit(); 我不知道,但你的第一个问题可能会导致第二个,因为事务不提交。 对于会议的好策略,你可以看看这个 。



文章来源: Hibernate, session, lazyloading