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

Spring Boot拉取OracleDB大量数据内存溢出与懒加载异常问题咨询

问题根因

你遇到的OOM问题本质是open-in-view=true时,整个请求生命周期都会绑定同一个Hibernate Session,你分页查询的所有实体都会被存入Session的一级缓存,不会被GC回收,250万条数据累计下来就会占满堆内存,调高内存也无法从根本上解决问题。

可行解决方案

方案一:保留全局open-in-view=true,导出业务主动清理一级缓存(改动最小,优先推荐)

不需要修改全局配置,也不影响其他接口的懒加载逻辑,只需要在导出业务中每页查询完成后主动清空Hibernate持久上下文释放内存即可,修改后的代码如下:

@Service
@Transactional
@AllArgsConstructor(onConstructor_ ={@Autowired})    
public class ExportServiceImpl {
     private ExportRepository exportRepository;
     // 注入EntityManager操作持久上下文
     private EntityManager entityManager;
    
    public ExportDto export(){
        List<ExportEntity> allData = new ArrayList<>();
        int page = 0;
        int size = 100000;
        List<ExportEntity> pageData;
        do {
            pageData = exportRepository.findAll(page, size);
            // 处理当前页数据(如格式转换、写入文件等)
            allData.addAll(pageData);
            // 清空一级缓存,释放已处理数据占用的堆内存
            entityManager.flush();
            entityManager.clear();
            page++;
        } while (!pageData.isEmpty());
        // 组装返回DTO逻辑
        return new ExportDto(allData);
    }
}

@Repository
public interface ExportRepository extends JpaRepository<ExportEntity,String> {
    @Query(value = "select * from {table} offset :page rows fetch next :size rows only", nativeQuery = true)
    List<ExportEntity> findAll(int page, int size);
}

方案二:全局保留open-in-view=true,仅导出接口禁用OIV

如果不想修改业务代码,也可以通过拦截器配置,仅排除导出接口的OIV拦截,其他接口的懒加载逻辑不受影响:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 匹配系统默认注册的OIV拦截器
        Optional<HandlerInterceptor> oivInterceptor = registry.getInterceptors().stream()
                .filter(interceptor -> interceptor instanceof OpenSessionInViewInterceptor)
                .findFirst();
        oivInterceptor.ifPresent(interceptor -> {
            // 排除导出接口路径,按你实际接口路径修改即可
            registry.addInterceptor(interceptor).excludePathPatterns("/export");
        });
    }
}

注意使用该方案时,需将导出方法的事务粒度调整为每页单独生效,避免事务持续持有Session导致缓存无法释放。

方案三:全局关闭open-in-view,按需为懒加载接口保活Session

如果想彻底避免OIV带来的内存泄露风险,可以全局关闭open-in-view=false,对需要用到懒加载的接口,在对应业务方法上添加@Transactional注解,保证事务周期内Session存活;或者通过Hibernate.initialize(代理对象)手动初始化懒加载关联属性,即可避免LazyInitializationException异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 15:24:04