我使用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实体并以相同的方式缓存它们,则调用Town#getResidents()
会返回对内存中与常驻缓存中存在的某些相同对象的引用?
本质上,Hibernate是否会重用以前在查询中返回的仍然有效的对象来填充新创建的集合?
对于我的一般方法或如何改进它的建议,我也不会提出任何批评。先感谢您! :)
答案 0 :(得分:2)
缓存是一个非常复杂的主题。您不必自己照顾缓存。这就是休眠second-level-cache的目的。
数据库抽象层(例如ORM)的优点之一 (对象关系映射)框架是 透明地缓存从基础存储中检索到的数据。 此 帮助消除频繁访问的数据的数据库访问成本。
您仍然必须将实体配置为可缓存,以及休眠应该如何积极地休眠,但是其余的将由休眠处理
WITH(NOEXPAND)
答案 1 :(得分:1)
如果堆消耗不是问题,或者生成的实例不是很多,那么您的方法也不错。我看到您已经在使用FetchType.EAGER
,这是重要的部分。
我想说您甚至不需要检索Resident
,您只需收集每个residents
的{{1}} Set<Resident>
。
一旦检索到所有实例,我也将明确Town
它们。
是的,Hibernate维护多个缓存级别。参见documentation。
如果我要问的话,为什么要使用JPA?毕竟,不是更底层的方法(也许使用MyBatis)会是更好的方法吗?依靠像Hibernate这样的重量级框架不是过大吗?
答案 2 :(得分:0)
我不同意关于缓存的公认答案。我还有另一个答案,在这里我详细解释了为什么我不喜欢休眠二级缓存hibernate second level cache with Redis -will it improve performance?的原因到目前为止,休眠二级缓存的使用并不是一种常见的缓存策略。造成这种情况的原因有很多:
与接受的答案相反,我建议您将缓存与持久性分离为简单的Pojos。并通过这些Pojoes管理缓存。
现在就您的模特而言。我不知道您要涵盖的功能是什么,但我强烈怀疑有人会与所有居民一起来一个小镇。我建议您删除OneToMant关系,从城镇到居民。基于此,我看到以下情况: