2014-11-21 118 views
3

在將實體ID持久化到數據庫之前,但在構造函數中立即爲實體分配ID會有巨大的價值:您的equals/hashcode實現變得微不足道,and it saves many headachesjpa序列ID的生成

當實體等同性基於==時,我看到了問題:代理進入會話,並且當它作爲真實對象被解包時,將得到equals(),返回false

而且當你重寫equalshashcode使用生成的ID,因爲僅在persist()產生的一個,所有非持續的實體有ID null,因此都彼此相等。

從我讀到的內容來看,當您使用傳統的ID生成技術(自動遞增)時,ID會在實體管理器刷新時生成。當您使用基於序列的解決方案時,它會持續生成。

這篇文章和我目前的理解說最簡單的解決方案是在創建時分配一個ID,而不是持續或刷新時間。並且序列看起來可以訪問,但JPA決定反對它。使用序列來獲取ID是很便宜的(正如您可以預取的那樣),JPA如何在對象構建時間內沒有提供至少一個選項來獲取基於序列的ID?如果實體實際上並沒有堅持到最後,那麼存在浪費一些ID的風險,但我認爲這不是一個大問題。

除此之外,就解決方案的簡單性和可理解性而言,唯一的「不妥協」似乎是UUID,它們有其自身的問題。

我錯過了什麼?是否有可能在某處某個JPA身份生成器或某個庫將基於序列並允許在施工時提供該ID?

回答

2

從寫作的角度來看,使用assigned identifier是最好的方法。它在所有entity state transitions中也是一致的,您甚至可以在JDBC級別對多個插入進行批處理。

當涉及到讀取和索引時,數字列執行得更好,並且分配的標識符是唯一邏輯密鑰(社會安全號碼)或唯一標識符(例如UUID)。使用應用程序級唯一分配的標識符非常複雜,因爲您可能有多個應用程序節點(在集羣中),或者希望在應用程序內以及從外部源(數據庫客戶端實用程序)同時插入同步插入。

對於數據庫分配的標識符,您需要考慮您的選擇如何影響沖洗。 Hibernate試圖推遲Persistence Context flushing up until the last possible moment。這種策略傳統上被稱爲事務性後寫。

後寫與Hibernate刷新更多地相關,而不是任何邏輯或物理事務。在交易過程中,刷新可能會發生多次。

刷新的更改僅對當前數據庫事務可見。在提交當前事務之前,其他併發事務不會看到任何更改。

IDENTITY requires flushing,而一個序列是非事務性的,因此它不需要刷新。 IDENTITY禁用JDBC插入批處理,並且不支持預分配。

JPA無法在實體構造時分配標識符,因爲新實例只能通過EntityManager.persist()調用持久化。 JPA需要明確的「實體狀態轉換」。

浪費序列標識符並不是什麼大問題。即使序列值存在差距,數據庫也能正常工作。使用bigint列可以保證您實際上不會用完序列標識符。非事務性序列標識符分配偶爾存在差距比事務性分配具有較高的死鎖爭用風險更好。

+0

我還是不明白。對於由序列支持的數字類型,如果預取序列值,您仍然可以批量寫入,但仍然可以獲得良好的索引,不需要刷新。在我有限的理解中,我沒有看到需要將持久化和實體分配給一個ID,所以我不明白爲什麼不在建造時分配一個先前保留的序列號作爲ID?特別是如果浪費不是問題。 – 2014-11-21 15:12:30

+0

所以,我會使用prefetched序列值,而不是UUID,在我看來,我得到的UUID(在客戶端減ID生成)沒有性能和空間的擔憂,但我沒有找到一個現成的解決方案(發電機),這讓我感到驚訝。 – 2014-11-21 15:19:24

+1

我建議你開始使用[pooled-lo optimizer](http://vladmihalcea.com/2014/07/21/hibernate-hidden-gem-the-pooled-lo-optimizer/)以及序列生成器。點擊此鏈接查看如何做到這一點。 – 2014-11-21 15:36:30