Spring Boot+Hibernate中findByCustomerAndProduct报AssertionFailure的解决方法
解决Hibernate AssertionFailure: force initializing collection loading错误
在Spring Boot项目中使用Hibernate时,调用CartItemRepository接口的findByCustomerAndProduct或findByCustomer方法时,触发org.hibernate.AssertionFailure: force initializing collection loading断言错误,无法正常检索CartItem数据。尝试为findByCustomerAndProduct方法添加@Query注解自定义查询,问题仍未解决。
相关代码
CartItem实体类
@Entity @Table(name = "cart_items") public class CartItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "customer_id") private Customer customer; @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "product_id") private Product product; private Integer quantity; }
CartItemRepository接口
public interface CartItemRepository extends CrudRepository<CartItem, Integer> { List<CartItem> findByCustomer(Customer customer); CartItem findByCustomerAndProduct(Customer customer, Product product); @Modifying void deleteByCustomerAndProduct(Customer customer, Product product); @Modifying @Query("UPDATE CartItem c SET c.quantity = ?1 WHERE c.product.id = ?2 AND c.customer.id = ?3") void updateQuantity(Integer quantity, Integer productid, Integer customerid); }
错误堆栈信息
org.hibernate.AssertionFailure: force initializing collection loading at org.hibernate.collection.spi.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:807) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:995) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:981) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:170) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:32) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:166) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:91) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:140) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:110) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.loader.ast.internal.SingleIdEntityLoaderStandardImpl.load(SingleIdEntityLoaderStandardImpl.java:72) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4325) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4315) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:599) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:572) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:224) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:363) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:113) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:75) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1241) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1094) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer.initializeInstance(EntitySelectFetchInitializer.java:197) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.internal.StandardRowReader.coordinateInitializers(StandardRowReader.java:153) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:98) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:143) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:32) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:166) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:91) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:140) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.loader.ast.internal.SingleIdLoadPlan.load(SingleIdLoadPlan.java:110) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.loader.ast.internal.SingleIdEntityLoaderStandardImpl.load(SingleIdEntityLoaderStandardImpl.java:72) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:4325) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4315) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:599) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:572) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:224) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:363) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:113) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:75) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1241) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1094) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer.initializeInstance(EntitySelectFetchInitializer.java:197) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.internal.StandardRowReader.coordinateInitializers(StandardRowReader.java:153) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.internal.StandardRowReader.readRow(StandardRowReader.java:98) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:143) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:32) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:443) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:166) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:91) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:102) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:305) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:246) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:546) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:363) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1032) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:457) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.hibernate.query.sqm.internal.QuerySqmImpl.getSingleResult(QuerySqmImpl.java:1062) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final] at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:193) ~[spring-data-jpa-3.0.0.jar:3.0.0] at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:90) ~[spring-data-jpa-3.0.0.jar:3.0.0] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:148) ~[spring-data-jpa-3.0.0.jar:3.0.0] at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:136) ~[spring-data-jpa-3.0.0.jar:3.0.0] at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136) ~[spring-data-commons-3.0.0.jar:3.0.0] at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120) ~[spring-data-commons-3.0.0.jar:3.0.0] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164) ~[spring-data-commons-3.0.0.jar:3.0.0]
解决方案
1. 排查循环关联与懒加载冲突
这个错误的核心原因是循环加载导致的集合初始化死循环:CartItem设置了EAGER加载Customer/Product,而Customer/Product中可能存在@OneToMany关联CartItem的懒加载集合,当Hibernate加载CartItem时,会触发Customer/Product的加载,进而触发其CartItem集合的初始化,形成循环。
2. 调整FetchType为LAZY
将CartItem中关联实体的FetchType从EAGER改为LAZY,仅在需要时手动加载关联实体:
@Entity @Table(name = "cart_items") public class CartItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne(fetch = FetchType.LAZY) // 改为LAZY @JoinColumn(name = "customer_id") private Customer customer; @ManyToOne(fetch = FetchType.LAZY) // 改为LAZY @JoinColumn(name = "product_id") private Product product; private Integer quantity; }
3. 移除不必要的级联操作
cascade = CascadeType.ALL会让CartItem的操作(如保存、删除)级联到Customer和Product,这不符合业务逻辑(删除购物车项不应该删除用户或商品),建议移除或按需设置级联类型:
@ManyToOne(fetch = FetchType.LAZ
相关产品推荐
相关产品推荐

