在对象身份很重要的冬眠/JPA的持久性



我正在使用Hibernate/jpa作为持续的后端,从本质上归结为用Java编写的游戏的mod。

在这种情况下,对我来说,我在主线程上很少查询数据库非常重要。这样做的同步虽然可能是不切实际的,因为我不得不从其他线程中调用游戏对象的方法,而这些方法通常不会起作用。这意味着我必须使用缓存对象在内存中尽可能多地做事,以最大化性能(因为使用内存要比等待查询以返回数据库的结果更快)。

说我的实体定义如下:

@Entity
class Town {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
    @OneToMany(mappedBy = "town", fetch = FetchType.EAGER) // use eager fetching to save on having to query the database later for this
    private Set<Resident> residents;
    // ... other fields and associated getters/setters
}
@Entity
class Resident {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;
    @ManyToOne(fetch = FetchType.EAGER) // use eager fetching to save on having to query the database later for this
    @JoinColumn(name = "town_id")
    private Town town;
    // ... otehr fields and associated getters/setters
}

我的问题是:

如果我要使用Hibernate检索所有居民实体,并将其存储在内存中(例如,使用hashmap),如果我要继续使用Hibernate检索所有城镇实体,并以相同的方式缓存它们,Town#getResidents()调用与居民缓存

中的内存中的某些对象返回引用。

本质上,Hibernate重新使用的静态valid对象是否以前在查询中返回以填充新创建的集合?

我也不会反对对我的一般方法的任何批评,也不反对我如何改善它的建议。先感谢您!:)

缓存是一个非常复杂的主题。您不必自己照顾自己的缓存。这就是Hibernates二级缓存的目的。

数据库抽象层(例如ORM)的优点之一 (对象相关映射)框架是他们的能力 透明的缓存数据从基础存储中检索到。有助于消除经常访问的数据的数据库访问成本。

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
class Resident {
...

如果堆消耗不是问题,或者生成的实例不是太多,那么您的方法还不错。我看到您已经在使用FetchType.EAGER,这是重要的部分。

我会说您甚至不需要检索Resident(S),您只能收集每个Townresidents Set<Resident>

一旦检索了所有实例,我也会显式 EntityManager#detach

是的,Hibernate保持了多个级别的缓存。请参阅文档。


如果我可以问,为什么要使用JPA?毕竟,更低级的方法,也许使用mybatis会成为更好的方法吗?依靠像冬眠等重量级框架不会过度杀伤?

我不同意接受缓存的答案。我还有另一个答案,详细解释了为什么我不喜欢冬眠的第二级缓存冬眠第二级缓存,而redis会改善性能?到目前为止,冬眠第二级缓存的使用不是常见的缓存策略。这样的原因有几个:

  • 休眠的第二级缓存非常低效。它使用默认的Java序列化,该序列化非常缓慢且内存非常遥不可及。
  • 经常使用Hibernate的第二层缓存您需要保持关系的一致性。一个这样的示例是您需要从集合中删除元素。如果您使用简单的Pojoes,保持一致性并不重要,但是当您开始将持久性逻辑与缓存混合在一起时,它开始变得非常烦人。
  • 如果您决定从纯第二层缓存到Hibernate的分布式缓存。复杂性不会以良好的方式飙升,那么您将学习艰难的方式为什么冬眠缓存效率低下。

我将与接受的答案建议相反,将您的缓存从持久性分离为简单的pojos。并通过这些pojoes管理缓存。

现在,从您的模型中。我不知道您涵盖了什么功能,但我强烈怀疑任何人都会与所有居民一起取得一个城镇。我会建议您删除从城镇到居民的单元关系。基于此,我看到以下方案:

  • 居民中心数据处理,您可能会在居民上重复命中。您可以决定缓存完整的居民加上城镇,或者,如果您不遇到同一居民,则可以决定仅缓存该镇。
  • 在同一地区的城镇和居民中均以居民为中心。您可以选择在您的居民和居民的同一钥匙下一起缓存,您将牺牲一些记忆是的。但是您将一口气直接受到记忆和城镇的打击。
  • 居民和城镇的两个缓存区域,但随后您需要为1个居民执行两个查找。就记忆而言,在性能方面更有效。
  • 仅缓存城镇。无论您决定什么,无论如何。我会个人不去冬眠的第二级缓存:)

最新更新