Vaadin Crud组件无法从Spring JPA加载数据及流操作异常求助
异常原因
你遇到的stream has already been operated upon or closed异常是Java Stream的特性导致的:Stream属于一次性消费的对象,只要执行过终端操作(比如count()、collect()、forEach()等),Stream就会被标记为已关闭,无法再执行后续的中间操作(比如filter()、sorted()、skip()等)。
你在fetchFromBackEnd方法里的逻辑触发了这个问题:
Stream<GuildTempChannelSettings> stream = tempChannelSettingsRepository.findByGuildId(this.guildId).stream(); // 这里调用count()是终端操作,直接消耗了stream log.info("Found {} entries", stream.count()); // 后续再操作stream就会抛出异常
解决方案
修改fetchFromBackEnd方法,先把查询结果存在List变量中,用List的size()方法打印日志,再基于List生成新的Stream做后续处理即可,修正后的代码如下:
@Override protected Stream<GuildTempChannelSettings> fetchFromBackEnd(Query<GuildTempChannelSettings, CrudFilter> query) { int offset = query.getOffset(); int limit = query.getLimit(); // 先把查询结果存为List List<GuildTempChannelSettings> settingsList = tempChannelSettingsRepository.findByGuildId(this.guildId); log.info("Found {} entries", settingsList.size()); // 从List重新生成Stream Stream<GuildTempChannelSettings> stream = settingsList.stream(); if (query.getFilter().isPresent()) { stream = stream .filter(predicate(query.getFilter().get())) .sorted(comparator(query.getFilter().get())); } return stream.skip(offset).limit(limit); }
额外优化建议
你当前的实现存在重复查询的问题:每次Crud组件刷新数据时,fetchFromBackEnd和sizeInBackEnd会各自调用一次findByGuildId查询全量数据,当数据量较大时会产生不必要的性能开销。如果后续数据量增长,你可以:
- 改用带分页、过滤、排序参数的JPA查询,避免每次拉取全量数据
- 也可以重写
AbstractBackEndDataProvider的相关方法,复用同一次查询的结果计算size和返回分页数据
内容的提问来源于stack exchange,提问作者Skyriiy
相关产品推荐
相关产品推荐

