You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@WebAppConfiguration时Spring Data JPA懒加载失效问题

拆解JPA懒加载测试的异常现象:为什么@WebAppConfiguration会“忽略”懒加载设置?

先把涉及的代码都贴出来,方便对照分析:

实体模型

@Entity 
public class User { 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE) 
    private Long id; 
    private String username; 
    @ManyToMany(fetch = FetchType.LAZY) 
    @JoinTable(
        name = "USER_ROLE", 
        joinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")}, 
        inverseJoinColumns = {@JoinColumn(name = "ROLE_ID", referencedColumnName = "ID")}
    ) 
    private List<Role> roles; 
    (...) 
} 

@Entity 
public class Role { 
    private String name; 
    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) 
    private List<User> users; 
    (...) 
} 

数据仓库

public interface UserRepository extends CrudRepository<User, Long> { 
    User findByUsername(String username); 
} 

控制器代码

@RestController 
@RequestMapping("/test") 
public class Controller { 
    @Autowired 
    private UserRepository userRepository; 

    @GetMapping 
    public void test(@RequestParam final String u) { 
        if(!this.userRepository.findByUsername(u)
            .getRoles().get(0)
            .getUsers().get(0)
            .getRoles().get(0)
            .getName().equals("Role1")) 
            throw new RuntimeException(); 
    } 
} 

主启动类

@SpringBootApplication 
public class Application { 
    public static void main(final String[] args) throws Exception { 
        SpringApplication.run(Application.class, args); 
    } 
} 

配置文件(application.properties)

spring.jpa.open-in-view=false

原测试类

@RunWith(SpringRunner.class) 
@WebAppConfiguration 
@ContextConfiguration(classes = Application.class) 
@AutoConfigureMockMvc 
public class ControllerTest { 
    @Autowired 
    private MockMvc mockMvc; 

    @Test 
    public void test() throws Exception { 
        this.mockMvc.perform(get("/test").param("u", "user1"))
            .andExpect(status().isOk()); 
    } 
} 

你的问题核心

按道理,仓库方法执行完事务就该结束,加上你已经关闭了spring.jpa.open-in-view,控制器里访问roles、user->role->users这些懒加载关联时,应该直接抛出LazyInitializationException才对,但实际调试时发现所有关联都被急加载了,测试还顺利通过。更奇怪的是,把@WebAppConfiguration换成@SpringBootTest后,就立刻抛出了预期的异常。

从Hibernate日志也能看到,查询用户时直接把User.roles给加载完了,完全没遵循FetchType.LAZY的设置。


问题根源:两种测试注解的上下文逻辑差异

这其实是@WebAppConfiguration和@SpringBootTest在初始化测试上下文时的规则不同导致的:

  1. @WebAppConfiguration的事务与EntityManager生命周期
    当你用@WebAppConfiguration + @ContextConfiguration时,测试的上下文并没有完整加载Spring Boot的所有自动配置逻辑。MockMvc处理请求时,仓库方法的事务虽然在方法结束后标记为终止,但Hibernate的EntityManager并没有立刻关闭——它的生命周期被延长到了整个请求处理的全程,包括控制器方法执行的阶段。
    这就意味着,当你在控制器里调用getRoles()、getUsers()时,EntityManager还是活跃的,Hibernate会自动触发关联的加载,自然不会抛出LazyInitializationException。

  2. @SpringBootTest的严格配置遵循
    @SpringBootTest是Spring Boot官方推荐的集成测试注解,它会完整加载Spring Boot的所有自动配置,包括你设置的spring.jpa.open-in-view=false。
    在这种模式下,仓库方法执行完毕后事务立即结束,EntityManager被及时关闭。控制器里再访问懒加载关联时,因为没有活跃的会话(Session)可以用来加载数据,就会抛出LazyInitializationException,这才是符合你预期的懒加载行为。

  3. Open Session in View的隐性生效
    虽然你配置了spring.jpa.open-in-view=false,但在@WebAppConfiguration的测试场景中,这个配置可能没有被正确读取和应用,相当于变相开启了Open Session in View模式——会话在整个请求周期保持打开,允许随时加载懒加载关联。而@SpringBootTest会严格解析并应用你的配置,确保Open Session in View处于关闭状态。


总结

简单来说,@WebAppConfiguration的测试方式更偏向传统Spring MVC的测试逻辑,没有完全适配Spring Boot的JPA事务管理规则,导致懒加载的限制没有生效;而@SpringBootTest会严格遵循你的配置,表现出符合预期的行为。如果要测试懒加载的正确性,建议使用@SpringBootTest来编写集成测试。

内容的提问来源于stack exchange,提问作者Whimusical

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:11:06