微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JPQL查询导致多次往返数据库,甚至是EAGER和JOIN FETCH

如何解决JPQL查询导致多次往返数据库,甚至是EAGER和JOIN FETCH

我试图理解为什么我的查询导致两次调用数据库。据我了解,我在查询中使用FETCH关键字加载了EAGER,这将导致一次往返,但是在这种情况下,情况并非如此。.感谢任何提示


        TypedQuery<Recipe> query = em.createquery("SELECT r FROM Recipe r" +
                "  LEFT JOIN FETCH r.ingredients ri LEFT JOIN FETCH r.author a WHERE r.id= :id ",Recipe.class);
        
        query.setParameter("id",id);

食谱类:

@Entity
@Table(name = "recipes")
@Getter
@Setter
@NoArgsConstructor
@JsonIdentityInfo(
        generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
@JsonSerialize(using = RecipeMetaSerializer.class)
public class Recipe implements Serializable {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;
    
    
    @ManyToOne(fetch = FetchType.EAGER)
    private User author;


    @OnetoMany(
            mappedBy = "recipe",orphanRemoval = true,fetch = FetchType.LAZY,cascade = CascadeType.PERSIST
    )
    private List<RecipeIngredient> ingredients;
}

一个联接表RecipeIngredient:

@Entity
@Table(name="recipe_ingredients")
@Getter
@Setter
@NoArgsConstructor
@IdClass(RecipeIngredientId.class)
public class RecipeIngredient implements Serializable {
    
    @Id
    @ManyToOne(fetch= FetchType.EAGER)
    private Recipe recipe;

    @Id
    @ManyToOne(fetch= FetchType.LAZY)
    private Ingredient ingredient;
.....
}

第二个联接表:

@Entity
@Table(name = "users")
@Getter
@Setter
@NoArgsConstructor
public class User {
    
    @Id
    private Long id;
    
    @OnetoMany(fetch = FetchType.LAZY,mappedBy = "author")
    private List<Recipe> recipes;
    
}

JPQL查询导致对数据库的以下两个调用均包含与表用户的左外部联接

select recipe0_.id as id1_6_0_,ingredient1_.ingredient_id as ingredie4_5_0__,user2_.img_url as img_url2_7_2_,user2_.username as username4_7_2_ from recipes recipe0_ **left outer join recipe_ingredients** ingredient1_ on recipe0_.id=ingredient1_.recipe_id **left outer join users** user2_ on recipe0_.author_id=user2_.id where recipe0_.id=?

select recipe0_.id as id1_6_0_,user1_.username as username4_7_1_ from recipes recipe0_ **left outer join users** user1_ on recipe0_.author_id=user1_.id where recipe0_.id=?

我希望一次联接到Users表,而不是两次。谢谢!

解决方法

第二个查询似乎是针对Recipe recipe

@Entity
public class RecipeIngredient {
    
    @Id
    @ManyToOne(fetch= FetchType.EAGER)
    private Recipe recipe;
 
}

只需使用FetchType.LAZY

@Entity
public class RecipeIngredient {
    
    @Id
    @ManyToOne(fetch= FetchType.LAZY)
    private Recipe recipe;
 
}

如果使用entityManager.find()方法,则不会有第二个查询。 recipe将已经在缓存中。

但是对于JPQL,Hibernate认为在第一个查询中找到的recipe不在缓存中,因此它会再次获取它(即使它是相同的recipe)。

建议

始终在所有地方使用延迟加载。在运行时禁用即时加载是不可能的。另外,如果您想将eager更改为lazy,将很难测试所有内容。

https://vladmihalcea.com/eager-fetching-is-a-code-smell

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。