多数据源配置中次级数据源调用findAll()出现懒加载无Session报错
问题根源
Spring Boot对标注@Primary的主数据源会自动套用全套JPA/Hibernate默认配置,其中就包含OpenEntityManagerInViewInterceptor——这个组件会在整个HTTP请求周期内保持Hibernate Session处于打开状态,直到JSON序列化完成,自然不会触发懒加载的Session缺失问题。
而次级数据源是手动配置的(从代码结构能看出来,手动创建了它的EntityManagerFactory、TransactionManager等核心组件),默认不会触发这些自动配置逻辑。请求处理完成后Session就会被关闭,当Jackson序列化实体时要加载标注LAZY的集合,就会出现"failed to lazily initialize... no Session"的报错。
当你交换两个数据源的@Primary注解后,原来的次级数据源变成主数据源,自动获得了默认配置的Session延长机制;原来的主数据源变成次级,失去了这个机制,所以问题会转移到新的次级数据源上。
可行解决方案
1. 给次级数据源添加Session延长拦截器
手动为次级数据源注册OpenEntityManagerInViewInterceptor,让它的Session也能保持到JSON序列化完成:
@Configuration @EnableJpaRepositories( basePackages = "com.example.linewebhookjava.repository.datasource2", entityManagerFactoryRef = "datasource2EntityManagerFactory", transactionManagerRef = "datasource2TransactionManager" ) public class Datasource2Config implements WebMvcConfigurer { // 已有的DataSource、EntityManagerFactory、TransactionManager配置代码... @Bean public OpenEntityManagerInViewInterceptor datasource2OpenEntityManagerInViewInterceptor() { OpenEntityManagerInViewInterceptor interceptor = new OpenEntityManagerInViewInterceptor(); interceptor.setEntityManagerFactory(datasource2EntityManagerFactory().getObject()); return interceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(datasource2OpenEntityManagerInViewInterceptor()); } }
2. 全局启用懒加载无事务支持(不推荐)
保留spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true配置,让Hibernate在无事务时临时创建Session加载懒加载数据,但这种方式会增加额外的Session创建开销,还可能引发事务一致性问题,只适合小项目临时救急。
3. 改为EAGER加载(简单但不灵活)
把实体类里的@ElementCollection(fetch = FetchType.LAZY)改成FetchType.EAGER,强制每次查询都加载关联集合。但这种方式会增加数据库查询压力,不适合关联集合数据量大的场景。
内容的提问来源于stack exchange,提问作者anno

