2016-10-06 3 views
0

Во-первых, извините, если я прошу очевидного или если вопрос принципиально немой по своей природе.JPA создайте запрос только один раз

Более академический вопрос должен знать, могу ли я создать запрос JPA (названный или любой другой), который охватывает или не зависит от EntityManager. В принципе, Подготовьте один раз подряд всегда. Я понимаю, что мы можем получить экземпляр запроса только из методов createXXXQuery объектов управления enitity, но все-таки есть ли другой способ?

Это то, что я пытаюсь сделать,

public class MyRepo { 
@PersistenceContext 
private EntityManager em; 

private Query aQueryIntentedtoBePreparedOnlyOnce; 

@PostConstruct 
public void prepareMyQuery(){ 
    aQueryIntentedtoBePreparedOnlyOnce = em.createQuery("...."); // Query with positional params 
    } 

    public void executeMyQuery(){ 
    aQueryIntentedtoBePreparedOnlyOnce.getResultList(); 
    } 
} 

Это выполняет совершенно в первый раз. Но во второй раз он говорит, что «Entity Manager закрыт». Я понимаю, что это связано с тем, что EM - это транзакция.

Этот EM управляется контейнером (JTA - Spring), поэтому я не могу распространять его на транзакции. И использование Session beans не является вариантом. Итак, есть ли способ создать этот запрос только один раз?

PS: Где находятся именованные запросы и кеширование запросов? с Именованными запросами я все еще, кажется, делаю createNamedQuery каждый раз. И что такое план кеша запросов, есть ли хорошие документы для него?

Еще один вопрос, почему запросы, созданные только на EM или в соединении (JDBC)? Разве мне не нужно знать, с какой БД я разговариваю, чтобы подготовить запрос? Это так, что никогда нельзя выполнить одно без правильной связи?

+1

Вы не можете. С простой спящей вы можете использовать 'DetachedCriteria', но в конце концов все равно должен стать экземпляром« Criteria »для выполнения, и для этого вам все еще нужен« Session »(или в терминах JPA« EntityManager »). Но зачем вам это делать? Вы не получите какой-либо/большой производительности (он будет использовать больше памяти), и фактический запрос (если настроен) кэшируется вашим драйвером JDBC. –

+0

@M. Deinum Мне не нужно это делать, просто интересно, не хватает ли я чего-то. И почему он потребляет больше памяти? вызвать запрос является членом моего объекта репо? Не меняется ли SQL с параметрами, какие использует JDBC-диск, кэшированный SQL? – anchreg

+0

Нет. Поскольку «PreparedStatement» кэшируется не с помощью связанного параметра. У вас больше объектов в памяти, следовательно, больше памяти. Теперь у вас очень короткий объект, который довольно быстро удаляется из памяти. –

ответ

2

Каждый объект Query привязан к определенному EntityManager и не может быть повторно использован в другом, точно так же, как каждый EntityManager привязан к одному соединению JDBC.

Именованные запросы - это способ кэширования скомпилированных запросов и полезных метаданных о них. Обычно, когда вы используете em.createQuery, он анализирует его каждый раз. Он может хранить некоторую информацию об этом в кеше, потому что он, скорее всего, снова встретится с тем же запросом, но это не требуется.

Запросы создаются путем вызова createStatement (возвращая Statement), prepareStatement (возвращающая PreparedStatement, который наследует предыдущую) или prepareCall (возвращение в CallableStatement, который наследует предыдущие два) на соединение JDBC. Эти объекты Statement не имеют интерфейса для переключения на другое соединение. В зависимости от драйвера они могут кэшироваться в приложении Java или на сервере. Заявление можно повторно использовать столько раз, сколько вы хотите в одном и том же соединении, но не на других.

+0

Хорошо. Благодарю. Итак, я не могу предотвратить компиляцию JPQL, но могу ли вы повысить производительность за счет использования Named запросов? – anchreg

+0

Полу-Да. Именованные запросы будут немного улучшать производительность, но не сильно. Поставщик JPA, скорее всего, сохранит их скомпилированными. Вам просто нужно создать их по имени. Обычно, хотя аннотации. – coladict