为了账号安全,请及时绑定邮箱和手机立即绑定

对象身份很重要的 Hibernate/JPA 的持久性

对象身份很重要的 Hibernate/JPA 的持久性

GCT1015 2022-06-23 17:57:06
我使用 Hibernate/JPA 作为持久性后端,本质上归结为一个用 Java 编写的游戏的 mod。在这种情况下,在主线程上尽可能少地查询数据库对我来说非常重要。尽管可能,但异步执行此操作是不切实际的,因为我必须从其他线程调用游戏对象的方法,而这通常不起作用。这意味着我必须使用缓存对象在内存中做尽可能多的事情,以最大限度地提高性能(因为使用内存比等待查询从数据库返回结果要快)。假设我有如下定义的实体:@Entityclass 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}@Entityclass 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 检索所有 Resident 实体,并将它们存储在内存中(例如,使用 HashMap ),然后如果我要继续使用 Hibernate 检索所有 Town 实体并以相同的方式缓存它们,将调用Town#getResidents()返回引用内存中的某些对象与驻留缓存中的对象相同吗?本质上,Hibernate 是否重用之前在查询中返回的仍然有效的对象来填充新创建的集合?我也不反对对我的一般方法或关于如何改进它的建议的任何批评。先感谢您!:)
查看完整描述

3 回答

?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

缓存是一个非常复杂的话题。您不必自己处理缓存。这就是休眠二级缓存的用途。


诸如 ORM(对象关系映射)框架之类的数据库抽象层的优点之一是它们能够透明地缓存从底层存储中检索到的数据。这 有助于消除频繁访问数据的数据库访问成本。


您仍然必须将实体配置为可缓存以及休眠应缓存的积极程度,但其余部分将由休眠处理


@Entity

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

class Resident {

...


查看完整回答
反对 回复 2022-06-23
?
波斯汪

TA贡献1811条经验 获得超4个赞

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

我想说你甚至不需要检索Resident(s),你可以收集residents Set<Resident>each 的Town

一旦检索到所有实例,我也会明确地显示EntityManager#detach它们。

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


如果我可能会问,您为什么使用 JPA?毕竟,更底层的方法,也许使用 MyBatis,不是更好的方法吗?依赖 Hibernate 之类的重量级框架是不是大材小用?


查看完整回答
反对 回复 2022-06-23
?
慕慕森

TA贡献1856条经验 获得超17个赞

我不同意关于缓存的公认答案。我有另一个答案,我已经详细解释了为什么我不喜欢使用 Redis 进行休眠二级缓存的休眠二级缓存 - 它会提高性能吗?到目前为止,使用休眠二级缓存并不是一种常见的缓存策略。有几个原因:

  • Hibernate 二级缓存效率很低。它使用默认的 java 序列化,这非常慢并且非常缺乏内存。

  • 经常使用休眠二级缓存需要保持关系的一致性。一个这样的例子是当您需要从集合中删除一个元素时。如果您使用简单的 pojoes,保持一致性通常不是什么大问题,但是当您开始将持久性逻辑与缓存混合时,它开始变得非常烦人。

  • 如果您决定从纯二级缓存转到带有休眠的分布式缓存。复杂性会以一种不好的方式飙升,然后您将很难了解为什么休眠缓存效率低下。

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

现在关于你的模型。我不知道您所涵盖的功能,但我强烈怀疑任何人都无法获取拥有所有居民的城镇。我建议您删除从城镇到居民的 OneToMant 关系。基于此,我看到以下场景:

  • 以居民为中心的数据处理,您可能会重复点击居民。您可以决定缓存完整的居民和城镇,或者如果您没有找到同一个居民,您可以决定只缓存城镇。

  • 将城镇和居民缓存在同一区域,您的处理以居民为中心。您可以选择在城镇和居民的同一个键下缓存在一起,您会牺牲一些内存是的。但是,您将一口气对记忆和城镇产生直接影响。

  • Resident 和 Town 的两个缓存区域,但是您需要为 1 resident 执行两次查找。在内存方面效率更高,在性能方面并非如此。

  • 缓存只镇。无论如何,无论您如何决定。我个人不会使用休眠二级缓存:)


查看完整回答
反对 回复 2022-06-23
  • 3 回答
  • 0 关注
  • 100 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号