JPA / Hibernate Spring @Transactional vs. JOIN FETCH - PullRequest
0 голосов
/ 03 марта 2020

Я сталкиваюсь с интересным решением LazyInitializationException. Чтобы предотвратить это (в OneToMany или ManyToMany), одним из известных решений является использование JOIN FETCH Query. Вы можете увидеть один из нескольких ее примеров: https://thoughts-on-java.org/best-practices-for-many-to-many-associations-with-hibernate-and-jpa/

Другим более простым решением является использование @Transactional из Spring. Например, вот так:

@DeleteMapping(value ="/product/{tagId}")
    @ResponseBody
    @Transactional
    public String deleteProductWithoutRelation(@PathVariable String product, Model model) {     
        Optional<Product> pr = productService.selectProduct(product);
        if (pr.isPresent()) {
            tag.get().getCustomer().size(); //usualy throws LazyInitializationException, 
                                            //without JOIN-FETCH Statment or @Transactional
        return deletedTagId;    
    }

Конечно, вы можете поместить @Transactional какого-либо метода из службы репозитория, чтобы инкапсулировать это решение. Итак, какие преимущества или недостатки обоих решений здесь?

1 Ответ

1 голос
/ 04 марта 2020

Здесь нужно распутать несколько вещей.

  1. @ Транзакционный означает, что ничего, кроме Spring не гарантирует, что соединение с базой данных (+ транзакция) будет закрыто и снова закрыто. Вот и все.
  2. Когда вы выбираете объект, содержащий ленивое поле, вы по сути говорите: я выбираю «некоторые» поля из моего объекта, кроме ленивого.
  3. Если вам позже понадобится это ленивое поле, потому что вы пытаетесь получить к нему доступ в своих представлениях (. html, .ftl,. jsp и т. Д.), Вам нужно выполнить еще один выбор, чтобы база данных для ее извлечения.
  4. Проблема: в этот момент, если вы вне метода @Transactional, у вас больше нет открытого соединения с базой данных, следовательно, LazyInitException.
  5. Подводя итог: Ваша выборка выдает 1 выбор для всех данных. Если вы НЕ делаете этого, вам нужно открытое соединение с базой данных / транзакция, которую дает вам @Transactional.

Рекомендация : вам следует попытаться получить все необходимые данные отображать представление с соответствующими инструкциями JPQL / Criteria / SQL и не полагаться на повторный выбор ленивых полей.

...