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

标签 java spring hibernate spring-boot

我希望我能使自己清楚并找到问题的核心。所以我有一个使用Spring-boot和Hibernate的应用程序。我将JPA仓库接口用于DAO。
我有一个名为NameSection的对象,该对象由7个不同的对象持有。
NameSection具有3个不同名称对象的列表(拉丁名称,通用名称,瑞典名称)。
当我打电话给service.getNameSection(30);例如,根据获得的位置,我会得到不同的结果。如果我从我的控制器中调用它,但该控制器的名称节的副本不完整,即使我调用了服务和getNameSection(nameSectionId),它似乎也不想对数据库进行查询。 (依次调用我的JPA存储库)。

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

当我在表单中提交一个对象(让我说一个Plant-object)并想转到相关的NameSection表单时,就会调用我正在努力使用的方法。

当我提交植物形式时,我将植物作为模型属性注入到我的方法中。
在此方法中,我获取NameSection-id并进行调用service.getNameSection(nameSectionId);它没有给我完整的姓名部分。在工厂形式中,我确实引用了名称部分,因此在我的CommonName列表(在NameSection中)中,我加载了一个CommonName。但是还有更多需要收集的地方,这就是为什么我打电话给我的服务。

我将其归结为:
如果我提交包含NameSection.id = 30的Plant-form并致电service.getNameSection(30);我将只用一个CommonName来获得nameSection。

如果我提交另一个包含另一个NameSection的Plant-form,但是我对service.getNameSection(30)进行了硬编码;并将其记录下来,就像测试一样,我确实获得了完整的NameSection(30)和完整加载的列表。

更令人沮丧的是,NameSection可以像我想要的那样为对象类型Fish起作用,该对象类型还包含一个NameSection。两种方法遵循完全相同的流程。在下面的方法中,只需将每个“植物”替换为“鱼”即可。

我的怀疑是春天或冬眠或某些事情需要捷径。我尝试在调用service.getNameSection(id);之前使Plant和NameSection无效。同样,但是即使我已经有一个不完整的副本,即使它为空,它也不会加载完整的nameSection。至少我是这样。我被困了好几天。

调用service.getPlant(plantId);也将加载完整的NameSection,但这在此特定方法中均无效。例如,在我的editPlant方法中,在同一Controller-class中工作正常。

因此,这是方法:

// 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)的工厂一起使用,它将在我的“ Hardcoded测试短语”中加载包含所有相关CommonNames的完整NameSection(id = 30)。

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

因此,我期望plantService.getNameSection(nameSectionId);始终为相同的nameSectionId ofc提供相同的结果。但是,如果内存中有可用的片段,似乎有些“智能快捷方式”使它跳过了几步,并且在这种情况下做出了错误的假设,或者仅仅是我吗?

我也许可以创建一个特殊的查询来询问缺少的CommonNames,但是必须有一种更整洁的方法。使我丧命的是,它确实可以在拥有名称节的7个不同对象中工作1个。当然它们之间应该有一些区别,但是我只是找不到。我发现的唯一区别是,在方法注入中,我最初在“ BindingResult theBindingResult”之后具有“ Model model”。我将其移动以与鱼类的工作方法相匹配,但是并没有任何区别。

我还尝试在我的service.getNameSection(id)方法中添加对getCommonNames()。size()的调用,以“收集惰性列表”,但没有区别。

有什么主意的专业人士吗?

最佳答案

我不想创建比我更多的文字墙,但我认为有人会希望看到提到的有效的鱼方法。

    @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。现在它可以按我的意愿工作了。除了我可能对数据库进行不必要的查询以解决其他问题。

关于java - 相同的查询方法结果不同;如果对象(未完全)加载到内存中,springboot和hibernate是否可以阻止查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58717377/

相关文章:

spring - 允许 OPTIONS HTTP 方法用于 oauth/token 请求

java - ActiveMQ Spring CLIENT_ACKNOWLEDGE 不起作用

没有参数的springboot WireMock mock

java - Spring Boot数据JPA持久化到数据库报错

java - 如何用数据库数据java和hibernate填充组合框

java - 如何查找并消除 Java 程序中的随机性来源

java - 遍历对象的数组列表

java - Java 11 上的 JFileChooser ,翻译成法语的问题

java - 使用 Java 获取 URL 并删除 HTML 字符串中的第一个图像

mysql - 如何为 JPA View 实体传递动态限制值?