JPQL 查询导致多次往返数据库甚至 EAGER 和 JOIN FETCH
JPQL Query results in multiple roundtrips to database even EAGER and JOIN FETCH
我想了解为什么我的查询会导致 2 次调用数据库。据我所知,我在查询中使用 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);
食谱Class:
@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;
}
首先加入table食谱成分:
@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;
.....
}
第二次加入table:
@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 查询导致以下两次对数据库的调用都包含 左外连接到 table 用户:
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=?
我希望加入用户 table 一次,而不是两次。有什么想法吗?谢谢!
看起来第二个查询是 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
。
,则很难测试所有内容
我想了解为什么我的查询会导致 2 次调用数据库。据我所知,我在查询中使用 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);
食谱Class:
@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;
}
首先加入table食谱成分:
@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;
.....
}
第二次加入table:
@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 查询导致以下两次对数据库的调用都包含 左外连接到 table 用户:
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=?
我希望加入用户 table 一次,而不是两次。有什么想法吗?谢谢!
看起来第二个查询是 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
。