Попытка понять, что происходит в спящем SQL, при добавлении объекта в коллекцию другого объекта. - PullRequest
0 голосов
/ 01 марта 2012

У меня есть два основных класса домена:

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...
}

Это файл отображения спящего режима для классов:

<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 голосов
/ 01 марта 2012

Я не уверен, но вы удивляетесь, почему не существует SQL, который загружает ваше событие, когда вы делаете:

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

На самом деле bean-компонент события, возвращаемый hibernate, не является простым pojo, но обычно это класс, усиленный некоторыми магическими поведениями, которые позволяют выполнять такие вещи, как отложенная загрузка и т. Д. (Проверьте динамические прокси, CGLib / Javassist ...)


Так что я не уверен, но думаю, когда вы звоните:

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

Создается только расширенный компонент событий, но SQL-запрос не запускается. Если вы сделаете вызов для нестационарного метода получения, sql, вероятно, будет запущен, потому что у него пока нет значения, возвращаемого для этого метода получения.

Наконец, я думаю, даже когда вы добавляете событие в коллекцию событий этого человека, sql запускать не нужно, поскольку для создания этой ссылки вам нужен только идентификатор события. Угадай, что? Расширенный bean-объект события, безусловно, уже знает этот идентификатор, поскольку вы указали его при использовании session.load -> расширенный класс инициализируется с id = 4

Это просто предположения, но попробуйте вызвать event.getSomething (), чтобы узнать, прав ли я;)

0 голосов
/ 01 марта 2012

Внутреннее соединение происходит из-за сопоставления человека со многими людьми и событий. Все события человека загружаются на Person.getEvents() до того, как событие может быть добавлено.

UPDATE

Для session.load() не требуется запрос к базе данных, поскольку при session.load() Hibernate предполагает, что сущность с данным идентификатором существует (исключение в противном случае), и просто генерирует прокси для данного идентификатора. С session.get() Hibernate перейдет в базу данных (если объект с этим идентификатором еще не находится в кэше сеанса или кэше 2-го уровня) и вернет постоянный экземпляр.

Я думаю, что когда вы отлаживаете свой код, вы также не увидите запрос на загрузку пользователя, пока не будет вызван person.getEvents().

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...