尝试理解在将实体添加到另一个实体中的集合时生成的SQL hibernate

时间:2012-02-29 21:35:26

标签: hibernate

我有两个基本的域类:

public class Event {

    private Long id;
    private String title;
    private Date date;
    // getters/setters...
}

public class Person {

    private Long id;
    private int age;
    private String firstname;
    private String lastname;
    private Set<Event> events = new HashSet();
    // getters/setters...
}

这是类的hibernate映射文件:

<class name="Event" table="EVENTS">
    <id name="id" column="EVENT_ID">
        <generator class="native"/>
    </id>
    <property name="date" type="timestamp" column="EVENT_DATE"/>
    <property name="title"/>
</class>

<class name="Person" table="PERSON">
    <id name="id" column="PERSON_ID">
        <generator class="native"/>
    </id>
    <property name="age"/>
    <property name="firstname"/>
    <property name="lastname"/>
    <set name="events" table="PERSON_EVENT">
        <key column="PERSON_ID"/>
        <many-to-many column="EVENT_ID" class="Event"/>
    </set>
</class>

如果我执行以下操作:

Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person person = (Person) session.load(Person.class, 8L);
Event event = (Event) session.load(Event.class, 4L);
person.getEvents().add(event);
session.getTransaction().commit();

执行以下SQL语句:

select
    person0_.PERSON_ID as PERSON1_1_0_,
    person0_.age as age1_0_,
    person0_.firstname as firstname1_0_,
    person0_.lastname as lastname1_0_
from PERSON person0_
where person0_.PERSON_ID=?

-- Why does this do an inner join?
select
    events0_.PERSON_ID as PERSON1_1_1_,
    events0_.EVENT_ID as EVENT2_1_,
    event1_.EVENT_ID as EVENT1_0_0_,
    event1_.EVENT_DATE as EVENT2_0_0_,
    event1_.title as title0_0_
from PERSON_EVENT events0_
inner join EVENTS event1_ on events0_.EVENT_ID=event1_.EVENT_ID
where events0_.PERSON_ID=?

insert into PERSON_EVENT (PERSON_ID, EVENT_ID) values (?, ?)

最后,问题是:

为什么session.load(Event.class, 4L);使用如上所示的内连接?而不只是在事件表上选择ID = 4的简单选择?

2 个答案:

答案 0 :(得分:0)

内部联接是由人和事件的多对多映射造成的。在添加事件之前,Person.getEvents()加载了一个人的所有事件。

<强>更新

session.load()不需要数据库查询,因为session.load() Hibernate假定存在具有给定id的实体(否则为Exception),并且只为给定的id生成代理。使用session.get() Hibernate将转到数据库(如果具有此id的实体尚未在会话缓存或二级缓存中)并返回持久性实例。

我认为在调试代码时,会在调用person.getEvents()之前查看加载此人的查询。

希望有所帮助。

答案 1 :(得分:0)

我不确定,但是你想知道为什么没有SQL加载你的事件:

Event event = (Event) session.load(Event.class, 4L);

实际上,hibernate返回的事件bean不是一个简单的pojo,但通常是由一些魔术行为增强的类,允许执行延迟加载等等...(检查动态代理,CGLib / Javassist ......)< / p>


所以我不确定,但我猜你打电话的时候:

Event event = (Event) session.load(Event.class, 4L);

仅创建增强型事件bean,但不会触发SQL查询。如果你在非瞬态getter上调用,可能会触发sql,因为它还没有为getter返回的值。

最后我猜即使你把事件添加到人的事件集合中,也不需要触发sql,因为要创建该链接,你只需要事件id。 你猜怎么着?自从你在使用session.load时提供它后,它肯定已经知道了增强的事件bean - &gt;增强的类初始化为id = 4

这些只是假设,但尝试调用event.getSomething()以查看我是否正确;)