SpringBoot Test整合JPA时FetchType.LAZY触发no session异常问题
问题1解答:仅测试username为什么会访问roles字段
你用到了Lombok的@Data注解,该注解会自动为实体类生成包含所有字段的toString、equals、hashCode方法。你调用的AssertJ断言方法hasFieldOrPropertyWithValue在断言失败时,会调用被测对象的toString方法打印完整对象信息用于错误提示,这一过程会遍历所有字段包括roles、jobs等关联集合,因此触发了对懒加载属性的访问。
问题2解答:为什么出现no Session报错
Hibernate的懒加载机制要求:访问未初始化的懒加载代理属性时,必须处于该对象关联的持久化Session上下文中。你的测试逻辑里,userRepository.findById执行完成后,对应的Session就会自动关闭,此时返回的User对象中roles、jobs都是未初始化的代理对象。后续断言失败调用toString访问代理属性时,Session已经关闭,无法完成代理初始化,就会抛出LazyInitializationException。
问题3解答:该场景最佳实践
- 优先修改断言逻辑:直接获取目标字段后再做断言,避免触发整个对象的
toString,示例代码如下:
@Test public void testQueryUser(){ User user1 = userRepository.findById(12L).orElse(null); // 直接断言username,不会访问其他关联字段 assertThat(user1.getUsername()).isEqualTo("adam"); }
- 调整JPA实体的Lombok注解:不要在带关联关系的JPA实体上直接使用
@Data,改用拆分的注解,同时排除关联字段避免自动生成的方法触发懒加载:
// 替换@Data为以下注解,排除所有关联属性避免toString/equals等方法触发懒加载 @Getter @Setter @ToString(exclude = {"roles", "jobs", "dept"}) @EqualsAndHashCode(exclude = {"roles", "jobs", "dept"}, callSuper = true) @NoArgsConstructor @AllArgsConstructor @DynamicUpdate @Entity @Table(name = "sys_user") public class User extends BaseEntity implements Serializable{ // 原有字段逻辑不变 }
- 确需在测试中访问懒加载属性的场景:给测试方法添加
@Transactional注解,让整个测试方法执行期间Session保持开启,支持懒加载属性的正常初始化。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

