问题描述
在具有 spring.jpa.open-in-view = true 的Spring Boot 2.1.2项目中,我们(经过几年没有此类问题)面临着 LazyInitializationException (在调用惰性集合后).
In a Spring Boot 2.1.2 project with spring.jpa.open-in-view=true, we are (after a couple of years not having this kind of issue) being faced with a LazyInitializationException upon calling a lazy collection.
使用JPA调试(logging.level.org.springframework.orm.jpa = debug)进行的堆栈跟踪表明,按照预期,在执行请求期间不会关闭会话,而与提交的单个事务无关:
The stack trace with JPA debugging (logging.level.org.springframework.orm.jpa=debug) indicates that, as expected, the session is not being closed during the execution of the request, independently of individual transactions being committed:
2021-03-22 23:37:25.198 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(211207390<open>)]
2021-03-22 23:37:25.199 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
2021-03-22 23:37:25.199 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(211207390<open>)] for JPA transaction
2021-03-22 23:37:25.199 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly
2021-03-22 23:37:25.200 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@6f7a9974]
2021-03-22 23:37:25.200 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2021-03-22 23:37:25.201 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(211207390<open>)]
2021-03-22 23:37:25.202 DEBUG 22668 --- [io-8020-exec-10] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.opsfactor.planning.model.domain.cluster.produto.ClusterProdutos.regrasAlocacaoClusterProdutos, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:597)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:216)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:576)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:147)
at org.hibernate.collection.internal.PersistentSet.iterator(PersistentSet.java:188)
at com.opsfactor.planning.model.projection.configuration.parametros.ClusterEParametrosProjection.getClusterProdutosDeMaterial(ClusterEParametrosProjection.java:740)
即使未关闭会话,也会始终在同一时间显示错误.实体和正在执行的代码是:
Even though the session is not closed the error shows up, always at the same point. The entity and code being executed are:
@Entity
public class ClusterProdutos implements Serializable {
...
---------> collection generating error
@OneToMany(mappedBy = "clusterProdutos",cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private Set<RegraAlocacaoClusterProdutos> regrasAlocacaoClusterProdutos = new HashSet<>();
...
}
我没有发现有关 spring.jpa.open-in-view = true 发生的此类异常的任何帖子/评论,所以我不仅仅希望解决该问题,背后的原因.可能是EAGER获取集合或只是使所有事务具有事务性都会使代码运行,但并不能回答问题.
I have not found any posts/comments on this kind of exception happening with spring.jpa.open-in-view=true, so more than just solving the issue I would like to understand the reason behind it. Probably EAGER fetching the collection or just making everything transactional will make the code run, but it will not answer the question.
到目前为止,我们已经尝试增加连接超时,空闲超时,最大生存时间和最大池大小-无效.
So far we have tried to increase the connection timeout, idle timeout, max lifetime and maximum pool size - to no effect.
该错误在我的Windows机器和我们的AWS生产服务器上均发生,该服务器运行在Linux上,数据库为MySQL 8
The error occurs both in my Windows machine and our AWS production server, which runs on their Linux flavour and the database is MySQL 8
更新:
当我注释掉下面的存储库调用时,错误停止,该调用是在实例化前一个实体之前进行的:
The error stops when I comment out the repository call below, which is made before the instantiation of the previous entity:
@Repository
public interface ProductionPlanLinhaRepository extends JpaRepository<ProductionPlanLinha,ProductionPlanLinhaCompositeKey> {
...
@Transactional
@Modifying(clearAutomatically = true, flushAutomatically = true) // https://www.baeldung.com/spring-data-jpa-modifying-annotation
@Query("UPDATE ProductionPlanLinha ppl "
+ "SET ppl.quantidadeSugestaoProducaoBaselineAtendida = ppl.quantidadeSugestaoProducaoBaseline, "
+ "ppl.quantidadeSugestaoProducaoItensNovosAtendida = ppl.quantidadeSugestaoProducaoItensNovos, "
+ "ppl.quantidadeSugestaoProducaoUpliftAtendida = ppl.quantidadeSugestaoProducaoUplift, "
+ "ppl.quantidadeSugestaoProducaoAjusteDemandaAtendida = ppl.quantidadeSugestaoProducaoAjusteDemanda, "
+ "ppl.quantidadeSugestaoProducaoAjusteSupplyAtendida = ppl.quantidadeSugestaoProducaoAjusteSupply "
+ "WHERE ppl.productionPlanLinhaCompositeKey.supplyPlan.id = :supplyPlanId")
public void resetPlanoProducaoRestritoBySupplyPlanId(Long supplyPlanId);
...
}
关于如何保留更新查询的任何想法?必须重置缓存,因为它不会随查询更新.
Any ideas as to how we can keep the update query? Cache reset is a must, as it is not updated with the query.
推荐答案
实际上,此问题与 Session
无关,这是修改后的查询,它清除了持久性上下文和您持有的对象您的Web层现在是一个分离的对象.
Actually the issue is not related to Session
here, it's the modifying query which clears the persistence context and the object you are holding upto your web layer, is a detached object now.
如果您在错误消息 AbstractPersistenceCollection
中检查该类,则该类具有此函数,该函数将被用来检查 session
是否存在
If you check the class in error message AbstractPersistenceCollection
it has this function which is called to check if session
is there or not
protected boolean isConnectedToSession() {
return session != null
&& session.isOpen()
&& session.getPersistenceContextInternal().containsCollection( this );
}
您可以看到这是&&
条件,最后一个条件是检查持久性上下文是否包含该集合,并且在这种情况下可能会引发错误,无论会话是否打开
As you can see this is the &&
condition, the last condition is checking if persistence context contains the collection and this might be throwing error in your case irrespective of session is open or not.
这篇关于LazyInitializationException,其中“在视图中打开"处于打开状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!