LazyInitializationException: почему Hibernate не может создать сеанс при отложенной загрузке? - PullRequest
0 голосов
/ 20 марта 2019

В моем проекте везде много методов @Transactional. Теперь из-за бизнес-логики я не хочу откатываться, когда у меня есть проблема, но хочу установить для моего объекта статус ошибки (он же сохранен в БД, поэтому определенно нет отката), поэтому я удалил несколько @Transactional для запуска.

Теперь проблема в том, что при ленивой загрузке нет сеанса, поэтому создается исключение LazyInitializationException.

Теперь вот мой следующий поиск неисправностей и поиск решения до сих пор:

  • Мы используем конфигурацию аннотаций, поэтому здесь нет конфигурации xml.

  • Для каждого действия, использующего базу данных, создается EntityManager (определяется как атрибут и @Autowired в службе), а затем удаляется (я отчетливо вижу его в журналах при добавлении конфигурации, чтобы увидеть их), что, по-видимому, нормально в соответствии с документацией Spring.

  • Использование @PersistenceContext или @PersistenceUnit, либо с EntityManagerFactory, либо с EntityManager не работает.

  • Я могу загрузить атрибут lazy -агрегата, который я хочу использовать, с Hibernate.initialize (), и тогда он не создаст исключение LazyInitializationException.

Теперь мой вопрос: почему спящий режим не может сделать это сам по себе? Мне кажется тривиальным, что если я использую отложенную загрузку, я хочу, чтобы Hibernate создал сеанс (что он, кажется, вполне способен сделать при выполнении Hibernate.initialize ()) для автоматической загрузки даты.

Был бы способ порождать новый менеджер сущностей для использования в моем методе, чтобы Hibernate не создавал и не воссоздывал его все время? Я действительно чувствую, что упускаю что-то простое в Hibernate, ленивой загрузке и сессиях, что делает весь этот беспорядок намного менее сложным.

Вот пример:

@Entity
@Table(name = "tata")
public class Tata {

    @Id
    @Column(name = "tata_id")
    private Long id;

    // getter / setter etc
}

@Entity
@Table(name = "toto")
public class Toto {

    @Id
    @Column(name = "toto_id")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tata_id")
    private Tata tata;

    // getter / setter etc
}

@Service("totoManager")
public class TotoManager extends GenericManagerImpl {

    @Autowired
    private EntityManager entityManager;
    @Autowired
    private TotoRepository totoRepository;

    public void doSomethingWithTotos() throws XDExceptionImpl {

        List<Toto> totos = this.totoRepository.findAll();

        for (toto toto : totos) {
        // LazyInitializationException here
            LOGGER.info("tata : " + toto.getTata().getId());
        }
    }
}

Ответы [ 2 ]

1 голос
/ 20 марта 2019

Попробуйте прочитать что-нибудь о Открыть сеанс в представлении , чтобы понять, почему Ленивая загрузка не работает вне сеанса / транзакции. Если вы хотите, вы можете установить свойство spring.jpa.open-in-view=true, и оно загрузит ваши лениво загруженные данные.

0 голосов
/ 20 марта 2019

Hibernate может сделать это сам. С установкой свойства hibernate.enable_lazy_load_no_trans=true (для весенней загрузки это должно быть spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true) вы можете загрузить любое ленивое свойство, когда транзакция закрыта. Этот подход имеет огромный недостаток: каждый раз, когда вы загружаете ленивое свойство, Hibernate открывает сессию и создает транзакцию в фоновом режиме.

Я бы рекомендовал извлекать ленивые свойства entityGraphs . Таким образом, вам не нужно перемещать постоянный контекст, делать верхний уровень или изменять тип выборки в ваших сущностях.

...