Spring / Hibernate:双向映射,不同步JPQL查询

时间:2022-09-11 16:27:25

In a bidirectional mapping between entities (e.g. @ManyToOne@OneToMany), the counterpart needs to be synchronized on every change, especially when using a 2nd level cache. This is usually done with helper methods. Those helper methods do not perform well if the Many part contains a lot of entries, because the whole set is fetched each time. A simple example would be an entity Store which has n Products, whereas n is very large. Adding a new Product to the Store would require the Store to fetch the whole list of Products to finally add it to the set (see code example below).

在实体之间的双向映射(例如@ManyToOne↔@OneToMany)中,对方需要在每次更改时进行同步,尤其是在使用二级缓存时。这通常使用辅助方法完成。如果Many部分包含大量条目,那么这些辅助方法不能很好地执行,因为每次都会获取整个集合。一个简单的例子是具有n个产品的实体商店,而n非常大。将新产品添加到商店将要求商店获取整个产品列表,最后将其添加到集合中(请参阅下面的代码示例)。

One could argue, that when modelling such a relation it would be better represented with an unidirectional association from the Product to the Store. We are using many JPQL queries in our application though. In JPQL, it comes very handy to join entities from both sides.

有人可能会争辩说,在建模这种关系时,最好用从产品到商店的单向关联来表示。我们在应用程序中使用了很多JPQL查询。在JPQL中,从双方加入实体非常方便。

Do you see any problems when mapping the @OneToMany relation in the Store entity, when Many actually means many and not just a few, and just make the field private, without getters and setters, provided that the whole relation is lazily fetched? As I understand, Hibernate just needs the field to map the relation. And if the set is private, no performance issues should occur?

在Store实体中映射@OneToMany关系时是否看到任何问题,当许多实际上意味着许多而不仅仅是少数几个,并且只是将该字段设为私有,没有getter和setter,只要整个关系被延迟取出?据我所知,Hibernate只需要该字段来映射关系。如果该集是私有的,那么不会出现性能问题?


The Product entity:

产品实体:

@Entity
@Table(name = "product")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Product {

  @ManyToOne(fetch = FetchType.LAZY)
  private Store store;

  // setter, getter, helper methods
}

The Store entity:

商店实体:

@Entity
@Table(name = "store")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Store {

  @OneToMany(mappedBy = "products", fetch = FetchType.LAZY)
  @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
  private Set<Product> products;

  // setter, getter, helper methods
}

1 个解决方案

#1


4  

No, there is nothing wrong with it, it's a technique I've used often as well. Of course just make sure that the field is not accessed reflectively in some context (like automatic toString builders and similar utilities you may be using).

不,它没有任何问题,这是我经常使用的一种技术。当然,只需确保在某些上下文中不会反复访问该字段(例如自动toString构建器和您可能使用的类似实用程序)。

Also, you don't need the @Cache annotation on it since you will never access the collection anyway, thus it will never be cached.

此外,您不需要@Cache注释,因为您永远不会访问该集合,因此它永远不会被缓存。

#1


4  

No, there is nothing wrong with it, it's a technique I've used often as well. Of course just make sure that the field is not accessed reflectively in some context (like automatic toString builders and similar utilities you may be using).

不,它没有任何问题,这是我经常使用的一种技术。当然,只需确保在某些上下文中不会反复访问该字段(例如自动toString构建器和您可能使用的类似实用程序)。

Also, you don't need the @Cache annotation on it since you will never access the collection anyway, thus it will never be cached.

此外,您不需要@Cache注释,因为您永远不会访问该集合,因此它永远不会被缓存。