2015-01-15 2 views
4

Я работаю над вопросом Hibernate, который включает в себя 2 отдельных зерен сущностей, определенных отдельно в своих классах:Hibernate @OneToMany вызывая множественные ЗЕЬЕСТ

  • магазин
  • StoreServer

Обратите внимание, что в магазине будет более одного StoreServer - следовательно, использование аннотации @OneToMany. Пожалуйста, смотрите фрагменты кода следующим образом:

магазин:

@Entity 
@Table(name="Store") 
public class Store implements Serializable { 
/** 
* Serializable class - generated UID 
*/ 
private static final long serialVersionUID = 5644190852867691168L; 

@Id 
@Column(name="STORE_NO", nullable=false) 
private int storeNumber; 

@Column(name="STORE_NAME", nullable=false) 
private String storeName; 

@Column(name="STORE_PHONE", nullable=false) 
private String storePhone; 

//other Store fields... 

@OneToMany(fetch = FetchType.EAGER) 
@JoinColumn(name="STORE_NO", insertable=false, updatable=false) 
private List<StoreServer> storeServers = new ArrayList<StoreServer>(); 

//getters and setters 

StoreServer:

@Entity 
@Table(name="Store_Server") 
public class StoreServer implements Serializable { 
/** 
* Serializable class - generated UID 
*/ 
private static final long serialVersionUID = -5410564578856243437L; 

@Id 
private StoreServerPK storeServerPK; 

@Column(name="IP_ADDRESS", nullable=true) 
private String ipAddress; 

//other StoreServer fields...getters and setters 

Поскольку StoreServer имеет составной первичный ключ, вот StoreServerPK:

@Embeddable 
public class StoreServerPK implements Serializable { 
/** 
* Serializable class - generated UID 
*/ 
private static final long serialVersionUID = -1401889029390423604L; 

@Column(name="STORE_NO", nullable=false) 
protected int storeNumber; 

@Column(name="SERVER_NO", nullable=false) 
protected String serverNumber; 

//getters and setters 

В присутствую, я получаю правильные результаты, но производительность неприемлемо МЕДЛЕННО. Я включил ведение журнала в Hibernate, и я вижу, что для каждого Хранилища создается отдельный запрос SELECT для получения связанных записей StoreServer.

В настоящее время в журналах я вижу один оператор SELECT для получения записей Store (получено более 200 результатов). Затем для каждого магазина создается новый оператор SELECT для получения записей StoreServer. Мой вопрос: почему Hibernate не выполняет соединение (выполняется один запрос)?

Возможно, я могу получить помощь в том, как сообщить Hibernate о запуске одного запроса, используя JOIN?

Спасибо

ответ

1

Это называется N + 1 проблема

Решение на самом деле зависит от того, как вы сделаете свой запрос - в случае, если вы используете критерии API вы должны использовать Root.fetch метод:

CriteriaBuilder qb = em.getCriteriaBuilder(); 
CriteriaQuery<Store> cq = qb.createQuery(Store.class); 

Root<Store> root = cq.from(Store.class); 
root.fetch(App_.storeServers, JoinType.LEFT); 

cq.select(root); 

return em.createQuery(cq).getResultList(); 

Если вы используете HQL, вы должны использовать ключевое слово fetch:

select distinct st from Store st left join fetch st.storeServers 

Это может быть хорошей идеей, чтобы проверить количество запросов, генерируемых Hibernate в модульных тестах с использованием в памяти базы данных, как H2 и JDBC Sniffer

+0

Привет Бедрин, спасибо за размещение ответа! Я использую HQL, и я следил за вашим советом и использовал ключевое слово 'fetch'. Hibernate теперь выполняет один запрос. Проблема в том, что я теперь повторяю записи магазина. В каждом магазине есть 3 StoreServers, и я получаю каждый Store 3 раза в моих результатах. Вы можете помочь с этим, пожалуйста? – user2318704

+0

@ user2318704 Я обновил ответ - вы должны использовать ключевое слово 'different' – bedrin

+0

Да, это сделал трюк ... СПАСИБО, Бедрин! – user2318704