2017-01-16 3 views
1

Я использую Hibernate 3.3.0.GA, и я заметил какое-то странное поведение, не документированное (я думаю).Различные SQL с помощью find и createQuery из диспетчера сущностей Hibernate

Я заметил, что entityManager.find разрешает отношения EAGER моей сущности и entityManager.createQuery нет.

Пер Например, если у меня есть объект:

@Entity 
public class Person { 

    @Id 
    private int id; 

    private String name; 

    @ManyToOne //EAGER by default in JPA 
    private Address address; 

} 

Сгенерированный SQL с entityManager.find(Person.class, 1L):

select 
    person0_.id as id1_1_, 
    person0_.address_id as address3_1_1_, 
    person0_.name as name1_1_, 
    address1_.id as id2_0_ 
from 
    Person person0_ 
left outer join 
    Address address1_ 
     on person0_.address_id=address1_.id 
where 
    person0_.id=? 

и сгенерированный SQL с entityManager.createQuery("SELECT p FROM Person where id = 1"):

select 
    person0_.id as id1_, 
    person0_.address_id as address3_1_, 
    person0_.name as name1_ 
from 
    Person person0_ 
where 
    person0_.id=? 

Итак, есть объяснение, почему это происходит? Для меня оба должны иметь одинаковое поведение.

Рабочий пример

Я создаю пример в моем хранилище показывает эту проблему, используя Hibernate 4.1.6.Final: https://github.com/dherik/hibernate-find-em-so-question. Просто используйте mvn clean install, и консоль распечатает запросы.

Обновлено

@KlausGroenbaek сказал 2.5.2 EclipseLink имеют такое же поведение в этих двух методов. Он также сделал пример Hibernate и получил аналогичный результат в двух методах (find он делает выбор соединения и createQuery он делает несколько выборок, как EAGER по определению).

+0

Оба запроса имеют одинаковое поведение, по крайней мере, с точки зрения того, что данные человека одинаковы для обоих. У вас есть определенный код, который имеет проблему? –

+0

После того, как Пользователь загружен, он должен иметь действительный экземпляр адреса или null. ManyToOne может быть только ленивым, если вы используете плетение для создания подкласса Address. Вы уверены, что нет второго запроса для выбора адреса, может быть, он не зарегистрирован? –

+0

Привет @TimBiegeleisen, да, у меня есть код (симуляция была там). К сожалению, я не могу поделиться этим кодом, но я могу создать пример в своем github и share. – Dherik

ответ

2

Я рассмотрел ваш пример и после его исправления работает точно так же, как HiberNate 5.2.5. find() использует соединение, а createQuery использует несколько выборок.

Причина, по которой вы не видите этого в своем примере, состоит в том, что у вас есть NO DATA в базе данных, найдите еще соединение, но поскольку в БД нет человека, ему не нужно смотреть для любого адреса, поэтому второй выбор отсутствует.

Однако вы заметите, что даже если вы добавите данные в свой пример, выбор из адреса не отображается. Это связано с тем, что адрес уже находится в контексте сохранения, когда вы использовали find(), поэтому нет необходимости загружать его снова. Фактически JPA MUST возвращает тот же самый экземпляр Java для адреса, если он уже загружен в Контекст сохранения. Если вы введете em.clear() или используете другой контекст сохранения (EntityManager), вы увидите выбор, потому что адрес еще не загружен.

Ваш пример является примером, но способ хранения управляемого приложения EntityManager в поле абсолютно запрещен, они всегда должны быть локальными переменными, когда вы управляете ими сами. Если вы используете управляемый контейнером EntityManager (Spring JavaEE), они могут быть полями, которые вводятся с помощью @PersistenceContext, но это только потому, что введенный EntityManager является прокси-сервером, в котором хранится состояние ThreadLocal.

Я использовал JPA широко с 2009 года, и вначале я сделал много ошибок, потому что я не понимал точно, что такое Контекст сохранения, поэтому у меня были перекрывающиеся EntityManager, неподдерживаемые двунаправленные отношения, и я не сделал полностью понимают состояния Entity или управляют контейнером или управляемым EntityManager. Многое из того, что я усвоил, был трудным (для меня это была отладка и чтение исходного кода EclipseLink); оглядываясь назад, я определенно купил книгу, чтобы получить общую картину, вместо того, чтобы решать проблемы случайным образом в Google, что я, хотя проблема была. Для всех, кто не прочитал документацию JPA, хорошую книгу или статью в отделе, сделайте свою услугу и узнайте из моих ошибок.

+0

Привет! Какие исправления вы сделали? Я инвертирую порядок запросов, а 'find' и' createQuery' по-прежнему имеют такое же поведение. Я использовал 'em.clear()' после 'find' и' createQuery', и не так уж и происходит. – Dherik

+0

Я разработал проект, преобразовал его в градиент (я отказываюсь использовать Maven и его подробную конфигурацию XML) и исправил проблемы, чтобы вы могли видеть запросы. Снова ваша проблема в том, что без данных в базе данных вы не видите всех запросов. https://github.com/QwertGold/hibernate-find-em-so-question –

Смежные вопросы