簡體   English   中英

持久化Hibernate / JPA,其中對象標識很重要

[英]Persistence with Hibernate/JPA where object identity is important

我使用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檢索所有Resident實體,並將它們存儲在內存中(比如使用HashMap),如果我要繼續使用Hibernate檢索所有Town實體並以相同的方式緩存它們, 將調用Town#getResidents()返回對Resident緩存中存在的內存中某些相同對象的引用

從本質上講,Hibernate是否重用了以前在查詢中返回的仍然有效的對象來填充新創建的集合?

我也不會反對任何批評我的一般方法或建議如何改進它。 先感謝您! :)

緩存是一個非常復雜的主題。 你不應該自己照顧緩存。 這就是休眠二級緩存的目的。

數據庫抽象層(如ORM(對象 - 關系映射)框架)的一個優點是它們能夠透明地緩存從底層存儲中檢索的數據。 有助於消除頻繁訪問數據的數據庫訪問成本。

您仍然必須將您的實體配置為可緩存以及hibernate應該如何積極地緩存,但其余的將由hibernate處理

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

如果堆消耗不是問題,或者生成的實例不是那么多,那么你的方法也不錯。 我看到你已經在使用FetchType.EAGER ,這是重要的部分。

我說你甚至不需要找回Resident ,你可以收集每個Townresidents Set<Resident>

一旦檢索完所有實例,我還會明確地將EntityManager#detach

是的,Hibernate維護多個級別的緩存。 文檔


如果我可能會問,你為什么要使用JPA? 畢竟,使用MyBatis的低級方法難道不是更好的方法嗎? 依賴Hibernate這樣的重量級框架是不是有點過分?

我不同意關於緩存的已接受的答案。 我有另一個答案,我已經詳細解釋了為什么我不喜歡使用Redis進行 hibernate二級緩存hibernate二級緩存 - 它會提高性能嗎? 使用hibernate二級緩存到目前為止還不是常見的緩存策略。 有幾個原因:

  • Hibernate二級緩存效率非常低。 它使用默認的java序列化,這非常慢,而且非常可靠。
  • 通常使用hibernate二級緩存需要保持關系的一致性。 一個這樣的例子是當你需要從集合中刪除一個元素時。 如果你使用簡單的pojoes,保持一致性並不是一件大事,但是當你開始將你的持久性邏輯與你的緩存混淆時,它開始變得非常煩人。
  • 如果您決定從純二級緩存轉移到具有休眠的分布式緩存。 復雜性將不會以一種好的方式飆升,然后你將學習為什么hibernate緩存效率低下的難點。

我接受的建議就是將你的緩存與持久性分離成簡單的Pojos。 並通過這些Pojoes管理緩存。

現在尊重你的模特。 我不知道你覆蓋了什么功能,但我強烈懷疑任何人都會和所有居民一起取城。 我建議你刪除從Town到Resident的OneToMant關系。 基於此,我看到以下場景:

  • 以居民為中心的數據處理 ,您可能會對居民進行重復點擊。 您可以決定緩存完整的居民加上城鎮,或者如果您沒有訪問同一居民,您可能決定只緩存該城鎮。
  • 緩存同一地區的城鎮和居民 ,您的處理以居民為中心。 您可以選擇在您居住在城鎮和居民的同一個密鑰下一起緩存,您將犧牲一些記憶。 但是你可以一次性直接擊中記憶和城鎮。
  • Resident和Town的兩個緩存區域 ,但是您需要為1個駐留執行兩次查找。 就記憶而言,在性能方面更有效率。
  • 只緩存城鎮 無論如何,無論你決定什么。 我個人不會用hibernate二級緩存:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM