【问题标题】:hibernate behavior explanation:休眠行为解释:
【发布时间】:2013-09-12 13:52:49
【问题描述】:

我有 3 个代码 sn-ps:

1:

            Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();
        Prepod prepod = (Prepod) session.load(Prepod.class, 1l);
        Student student = (Student) session.load(Student.class, 1l);

        Hibernate.initialize(prepod.getStudents());
        Hibernate.initialize(student.getPrepods());

        session.getTransaction().commit();
        session.flush();
        session.close();
            List<Student> students = new ArrayList<Student>();
     students.add(student);

     List<Prepod> prepods = new ArrayList<Prepod>();
     prepods.add(prepod);

     prepod.setStudents(students);
     student.setPrepods(prepods);


     session = HibernateUtil.getSessionFactory().openSession();
     session.beginTransaction();
     session.update(student);

     session.getTransaction().commit();
     session.close();

第一个 sn-p 有效,我看到了这样的日志:

Hibernate: select prepod0_.id as id1_1_1_, prepod0_.name as name2_1_1_, students1_.prepods_id as prepods1_1_3_, student2_.id as students2_2_3_, student2_.id as id1_0_0_, student2_.age as age2_0_0_, student2_.name as name3_0_0_ from prepod prepod0_ left outer join prepod_Student students1_ on prepod0_.id=students1_.prepods_id left outer join Student student2_ on students1_.students_id=student2_.id where prepod0_.id=?
Hibernate: select student0_.id as id1_0_1_, student0_.age as age2_0_1_, student0_.name as name3_0_1_, prepods1_.students_id as students2_0_3_, prepod2_.id as prepods1_2_3_, prepod2_.id as id1_1_0_, prepod2_.name as name2_1_0_ from Student student0_ left outer join prepod_Student prepods1_ on student0_.id=prepods1_.students_id left outer join prepod prepod2_ on prepods1_.prepods_id=prepod2_.id where student0_.id=?
Hibernate: update Student set age=?, name=? where id=?

2:从1中删除

            Hibernate.initialize(prepod.getStudents());
        Hibernate.initialize(student.getPrepods());

我们有:

 Session session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();
    Prepod prepod = (Prepod) session.load(Prepod.class, 1l);
    Student student = (Student) session.load(Student.class, 1l);

    session.getTransaction().commit();
    session.flush();
    session.close();
        List<Student> students = new ArrayList<Student>();
 students.add(student);

 List<Prepod> prepods = new ArrayList<Prepod>();
 prepods.add(prepod);

 prepod.setStudents(students);
 student.setPrepods(prepods);


 session = HibernateUtil.getSessionFactory().openSession();
 session.beginTransaction();
 session.update(student);

 session.getTransaction().commit();
 session.close();

结果:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
    at logic.Prepod_$$_javassist_1.setStudents(Prepod_$$_javassist_1.java)
    at logic.Main.main(Main.java:43)

3:更多删除

session.close();

session = HibernateUtil.getSessionFactory().openSession();

因此我们有:

    Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();
        Prepod prepod = (Prepod) session.load(Prepod.class, 1l);
        Student student = (Student) session.load(Student.class, 1l);
session.getTransaction().commit();
        session.flush();
List<Student> students = new ArrayList<Student>();
        students.add(student);

        List<Prepod> prepods = new ArrayList<Prepod>();
        prepods.add(prepod);

        prepod.setStudents(students);
        student.setPrepods(prepods);
        session.beginTransaction();
        session.update(student);


        session.getTransaction().commit();
        session.close();

这段代码的结果: 它有效,我看到了这样的日志:

Hibernate: select prepod0_.id as id1_1_1_, prepod0_.name as name2_1_1_, students1_.prepods_id as prepods1_1_3_, student2_.id as students2_2_3_, student2_.id as id1_0_0_, student2_.age as age2_0_0_, student2_.name as name3_0_0_ from prepod prepod0_ left outer join prepod_Student students1_ on prepod0_.id=students1_.prepods_id left outer join Student student2_ on students1_.students_id=student2_.id where prepod0_.id=?
Hibernate: select student0_.id as id1_0_1_, student0_.age as age2_0_1_, student0_.name as name3_0_1_, prepods1_.students_id as students2_0_3_, prepod2_.id as prepods1_2_3_, prepod2_.id as id1_1_0_, prepod2_.name as name2_1_0_ from Student student0_ left outer join prepod_Student prepods1_ on student0_.id=prepods1_.students_id left outer join prepod prepod2_ on prepods1_.prepods_id=prepod2_.id where student0_.id=?
Hibernate: insert into prepod_Student (prepods_id, students_id) values (?, ?)

特别注意这一行:

Hibernate: insert into prepod_Student (prepods_id, students_id) values (?, ?)

我不理解这种行为。你能解释一下为什么我会看到这些结果吗?

更新 前置:

@Entity
@Table(name = "prepod")
public class Prepod {

    private Long id;
    private String name;
    @Column
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    List<Student> students = new ArrayList<Student>();

    @ManyToMany(fetch=FetchType.EAGER)
    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    public void setId(Long i) {
        id = i;
    }

学生:

@Entity
@Table(name = "Student")
public class Student {

    private Long id;
    private String name;
    private Long age;
    private List<Prepod> prepods = new ArrayList<Prepod>();

    @ManyToMany(mappedBy = "students",fetch=FetchType.EAGER)
    public List<Prepod> getPrepods() {
        return prepods;
    }

    public void setPrepods(List<Prepod> prepods) {
        this.prepods = prepods;
    }

    public Student() {
        name = null;
    }

    public Student(Student s) {
        name = s.getName();
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    @Column(name = "name")
    public String getName() {
        return name;
    }

    @Column(name = "age")
    public Long getAge() {
        return age;
    }

    public void setId(Long i) {
        id = i;
    }

    public void setName(String s) {
        name = s;
    }

    public void setAge(Long age) {
        this.age = age;
    }
}
}

【问题讨论】:

    标签: java hibernate jpa orm


    【解决方案1】:

    Hibernate 使用其自定义 proxiesHibernateProxy 包装延迟加载的集合和对象。每个都有一个LazyInitializer 实例来初始化对象(因为它还没有完全加载)。

    这些LazyInitializer 实例扩展AbstractLazyInitializer

    AbstractLazyInitializer.initialize() 方法有以下(我们感兴趣)

    public final void initialize() throws HibernateException {
        if ( !initialized ) {
            if ( specjLazyLoad ) {
                specialSpecjInitialization();
            }
            else if ( session == null ) {
                throw new LazyInitializationException( "could not initialize proxy - no Session" );
            }
            ...
        }
    }
    

    在你的第一个 sn-p,你调用

    Hibernate.initialize(prepod.getStudents());
    Hibernate.initialize(student.getPrepods());
    

    在关闭Session之前,它会初始化Hibernate proxies,即。 prepodstudent 对象。所以他们的initialized 标志设置为true,并且所有未来与对象的交互都会跳过if 块。

    在您的 second sn-p 中,您不会初始化 proxies 并关闭 Session。当你尝试打电话时

    prepod.setStudents(students);
    

    它会失败,因为initialized 是假的,而sessionnull

    else if ( session == null ) {
        throw new LazyInitializationException( "could not initialize proxy - no Session" );
    }
    

    在你的第三个 sn-p中,你没有关闭Session所以调用

    prepod.setStudents(students);
    

    只会不间断地进行初始化。

    【讨论】:

    • 在所有示例中,我都使用 EAGER 初始化。我认为它会加载关系集合。
    • @user2674303 继续发布您的实体映射。
    • @User 你比我更适合检查,但是即使你有 EAGER 加载的集合,Hibernate 仍然代理你的类。
    • @user2674303 使用调试器。您会注意到 prepod 引用的类类型实际上是 Prepod_$$_javassist_1 类型的代理。
    猜你喜欢
    • 1970-01-01
    • 2012-08-05
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    相关资源
    最近更新 更多