2015-12-10 5 views
3

Я начинаю весну Jpa. У меня возникает ошибка. Я хочу знать, каковы преимущества и недостатки:
- Обращайтесь со всем бизнесом в классе Service и многократно звоните в Jpa Repository, который содержит только базовые операции, такие как CRUD, getList ....
Vs
- Сделайте длинный запрос @Query в Jpa Repository.Spring Jpa Service вызывает vs Jpa query

+1

Первый не имеет смысла. У пользователя уже есть адреса, и все, что вам нужно получить к ним, это вызвать 'user.getAddresses()'. Второй тоже не имеет большого смысла. Левое соединение в запросе совершенно бесполезно. Если вы хотите, чтобы этот запрос загружал пользователя с его адресами в одном запросе (и не полагался на ленивую загрузку для получения адресов), тогда запрос должен быть 'select different u из User u left join fetch u.addresses, где u .id =: id'. –

+0

Во-первых, что, если это ленивая нагрузка? Я не могу получить адреса, вызвав 'user.getAddresses()'. И зачем мне здесь «особенный»? Весь список отличается. Пропустите пример, вопрос в том, что в моем примере это то же самое, я имею в виду количество раз, когда он открывает соединение с базой данных, количество запросов и прокси-доступа. –

+1

Lazy-loading не означает, что «адреса никогда не будут загружены». Это означает, что «адреса будут загружены, когда они вам понадобятся». Так что да, вызывая, например, user.getAddresses(). Size() будет выполнять дополнительный запрос для загрузки адресов, заполнения списка адресов пользователя и последующего возврата количества адресов пользователя. Разница нужна, потому что в противном случае вы получите список из 3 пользователей, если у пользователя есть 3 адреса, а не список из 1 пользователя. –

ответ

2

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

Например, вы можете загрузить человека и изменить его контактный адрес, как это:

Person person = personRepository.find(personId); 
for (Address address : person.getAddresses()) { 
    if ("CONTACT_ADDRESS".equals(address.getType()) { 
    address.setCity("London"); 
    } 
} 

Все необходимые данные извлекаются и все изменения, сохраняются в БД.

Хотя это легко и просто, иногда могут возникать проблемы с производительностью, особенно если вам нужно загрузить только один адрес, а не все адреса. Или, если вам всегда нужны все адреса и вы хотите загрузить их в одном запросе вместе с человеком.

Тогда это хорошее решение для внедрения нового оптимизированного запроса в репозиторий. Например, запрос, который будет загружать все адреса с fetch join и не требует дополнительного ленивого (автоматический) запроса для загрузки их, когда вы перебирать адреса:

@Query("select distinct u from User u left join fetch u.addresses where u.id = ?") 
public List<User> findWithAddresses(Long id); 

Это не потребует, чтобы изменить код выше, кроме для переключения метода find() для findWithAddresses(). Но в фоновом режиме будет выполняться только один SQL-запрос вместо нескольких SQL-запросов.

+0

Да! это то, что я ищу. Кстати, знаете ли вы, когда соединение с базой данных заимствовано из пула соединений? Когда он отпустит соединение? –

+0

Соединение обычно назначается во время транзакции, поэтому оно «заимствовано» при запуске транзакции и освобождается при фиксации или откате. Но я не уверен, что это конкретная реализация, и возможно, что entitymanager поддерживает назначенное соединение до закрытия, но это было бы довольно глупо. – OndrejM