相同的查询方法不同的结果;如果对象(未完全)加载到内存中,springboot或hibernate是否可以阻止查询



我希望我能把自己说清楚,了解问题的核心。所以我有一个应用程序,我使用Spring引导和hibernate。我为DAO使用JPA存储库接口。我有一个名为NameSection的对象,它由7个不同的对象组成。NameSection有3个不同名称对象的列表(拉丁名称、通用名称、瑞典名称)。当我呼叫我的服务时。getNameSection(30);例如,根据我调用它的位置,我会得到不同的结果。如果我从我的控制器调用它,我有一个不完整的名称部分副本,它似乎不想查询我的数据库,即使我调用了我的服务和getNameSection(nameSectionId);(这反过来又称为我的JPA存储库)。

Spring引导或Hibernate是否可能停止对我的数据库的查询,因为它的内存中有它认为完整的NameSection?

当我在表单中提交一个对象(比如Plant对象)并想转到相关的NameSection表单时,就会调用我正在处理的方法。

当我提交Plant表单时,我会将植物作为modelAttribute注入到我的方法中。在这个方法中,我获取NameSection id并调用服务.getNameSection(nameSectionId);它没有给我完整的名字部分。在工厂表单中,我确实引用了名称部分,因此在我的CommonName列表(在namesection中)中,我有一个加载的CommonName。但还有更多的东西要收集,这就是为什么我打电话给我的服务。

我把它归结为:如果我提交了包含NameSection.id=30的工厂表格,并且我调用service.getNameSection(30);我将获得只有一个CommonName的nameSection。

如果我提交了另一份包含另一个NameSection的工厂表格,但我硬编码了service.getNameSection(30);并将其记录下来,就像测试一样,我确实得到了完整的NameSection(30)和完全加载的列表。

更令人沮丧的是,对于对象类型Fish,NameSection可以像我所希望的那样工作,它也包含NameSection。两种方法遵循完全相同的流程。在下面的方法中,只需将每个"植物"替换为"鱼",就可以了。

我怀疑春天或冬眠之类的事情走捷径。在调用service.getNameSection(id)之前,我尝试取消Plant和NameSection;如果我已经有一个不完整的副本,即使它为空,它也不会加载完整的nameSection。至少在我看来是这样。我已经被困了好几天了。

调用服务.getPlant(plantId);也将加载完整的NameSection,但这在这个特定的方法中也不起作用。例如,在同一个Controller类中的editPlant方法中运行良好。

所以,这就是方法:

// Process Plant form
@RequestMapping("/processPlantForm")
public String savePlantForm(Model model,
@RequestParam("saveButt") String saveButt,
// plant holds an incomplete namesection at this point
@Valid @ModelAttribute("plant") Plant plant, 
BindingResult theBindingResult){
...snipped validation...

plantService.savePlant(plant);
if (saveButt.equals("Edit NameSection")) {
// Here is the problem section!!
NameSection nameSec = 
plantService.getNameSection(plant.getNameSection().getId());
System.out.println("common names size: " + nameSec.getCommonNames().size());
// Hardcoded test phrase         
NameSection secNameSec = plantService.getNameSection(30);       
System.out.println("common names size: " + secNameSec.getCommonNames().size());
model.addAttribute("plant", plant);
model.addAttribute("nameSectionForm", new NameSectionForm(nameSec));
model.addAttribute("inflateNameSection", true);
return "form/create-plant";
}
else {      
return "redirect:/listPlant";
}
}

因此,对于持有id为30的NameSection的工厂,使用这种方法,它将在两个"getNameSection(id)"-调用中只加载一个CommonName(与modelAttribute中不完整的NameSection匹配)的NameSection(id=30)。

将这种方法与任何其他没有NameSection(id=30)的工厂一起使用,它将加载一个完整的NameSection(id=30),其中包含我的"硬编码测试短语"中的所有相关CommonNames。

在这两种情况下,我都会得到与NameSection相关的所有瑞典名字和所有拉丁名字,可能是因为它们都是ModelAttribute中不完整的NameSection中的空列表。

所以,我期望plantService.getNameSection(nameSectionId);对于相同的名称SectionId of c,始终给出相同的结果。但是,如果内存中有可用的片段,并且在这种情况下它做出了错误的假设,或者只有我,那么一些"聪明的捷径"似乎会让它跳过几个步骤?

我也许可以创建一个特殊的查询来查找缺少的CommonNames,但必须有一个更整洁的方法。让我头疼的是,它确实能处理7个不同对象中的1个,这些对象都有名称部分。当然,它们之间应该有一些差异,但我就是找不到。我发现的唯一差异是,我最初在方法注入中的"BindingResulttheBindingResult"之后有"Model Model"。我把它移到与鱼类的工作方法相匹配的地方,但没有任何区别。

我还尝试在我的service.getNameSection(id)-方法中添加一个对getCommonNames().size()的调用来"收集懒惰列表",但没有任何区别。

有专业人士知道发生了什么事吗?

我不想创建比我更多的文本墙,但我想有人会想看到提到的workingfish方法。

@RequestMapping("/processFishForm")
public String processFishForm(Model model,
@RequestParam("saveButt") String saveButt,
@Valid @ModelAttribute("fish") Fish fish,           
BindingResult theBindingResult) {

// this is the snipped validation from plant-method example above
if (theBindingResult.hasErrors()) {
System.out.println(theBindingResult.getAllErrors());
return "form/create-fish";
}

fishService.saveFish(fish);

if (saveButt.equals("Edit NameSection")) {
NameSection nameSec = fishService.getNameSection(fish.getNameSection().getId());
model.addAttribute("inflateNameSection", true);
model.addAttribute("fish", fish);
model.addAttribute("nameSectionForm", new NameSectionForm(nameSec););
return "form/create-fish";
} 
else {
return "redirect:/listFish";
}
}

FishService和PlantService都有完全相同的getNameSection(id)方法,根据我的测试,它们是100%可互换的。

更新所以我为CommonNames创建了一个新的DAO(JpaRepository接口)(因为我没有),并创建了自定义方法:

List<CommonName> findByNameSection(NameSection nameSection);

然后在服务中,当我调用NameSection时,服务也会调用该方法,以确保我得到所有的CommonNames。现在它按我的意愿工作。除了我可能对数据库进行不必要的查询以修复其他问题。

更新2:我变得更聪明了,如果有人遇到类似的问题,我需要/寻找的是一种刷新对象的方法。由于我使用JpaRepository,我在谷歌上搜索并找到了实现刷新方法的最简单方法。这对我来说有点太复杂了,在可能没有人关心的时候,我不能去低谷,但我用了这个例子,效果很好。https://www.javabullets.com/add-entitymanager-refresh-spring-data-repositories/

最新更新