2012-01-18 50 views
0

我需要在spring-jpa(hibernate)驅動的web應用程序中實現一個實體的GetOrCreate(我稱之爲ensureExists)。
我有一個分層的應用程序(WS/Services/DAL/Datastore),我想在服務層(spring驅動)中實現這個功能。
的基本思路是:如何使用JPA會話實現併發GetOrCreate?

  1. 查找實體
  2. 如果找到返回。
  3. 否則堅持實體。
  4. 如果一切正常返回它。
  5. 如果發生了唯一約束違規,請嘗試再次查找實體並將其返回。

問題的事實,一旦有異常拋出Hibernate的Session應該關閉並重新打開(從Session的documentation),這使得第5步無效,但我還是想封裝在服務層這一邏輯(出現並沒有它駐留在DAL或WS中)。

我很樂意聽到關於如何解決這個問題的建議,我有一個想法,但我希望在發佈之前聽到一些意見,以避免向答案傾斜。

預先感謝

更新
溶液我想到如下:
重構階段3到封裝作用域服務具有單一ensureExists方法(使用泛型),它接受所述道這種類型和實體,並具有REQUIRES_NEW的傳播。這個方法會嘗試持久化,如果失敗,當然會拋出一個將被原始服務捕獲的異常,並且如果該異常被拋出,它將嘗試持久化。
我很想談談如何以其他方式實現這一點。
如果沒有人會在幾天內另外提出建議,我會以代碼示例的形式發佈此答案並接受它。

+0

我會按照你的計劃去做,除非我將步驟1到步驟4放在REQUIRES_NEW的服務中。 – 2012-01-20 07:12:58

+0

@JB Nizet爲什麼你認爲步驟1,2,4需要進行交易?另外,在我看來,邏輯上只有第3步處於不同的抽象層次,所以有理由讓它坐在不同的服務中。所有其他步驟都具有相同的抽象級別(我認爲)。 – Ittai 2012-01-20 13:07:34

+0

我剛剛發現它有一個「getOrCreate」方法,它可以拋出異常,並且如果我想從外部重試,可以更清晰。它也將特定用例的重試邏輯(可以完全通用,提取給代理或攔截器)分離出來。而且它還允許使用創建的實體執行其他操作,而不僅僅是返回它。在你的系統中,你得到的實體被連接,如果被創建,則被分離。 – 2012-01-20 13:12:52

回答

0

要找到實體,您可以使用條件api + reflection來填充所有重要屬性並按樣本對象進行搜索。 要解決協調問題,請考慮悲觀鎖定。 當你完成加載時,只需在該對象上加鎖,並在所有事務完成後釋放此鎖。 不知道這是否是最好的選擇,但你永遠不應該在這裏例外。

+0

我可能是錯的,但我認爲在「find」步驟需要條件(索引列上的單列列除外)的情況下,您將無法使用悲觀鎖定。 – 2012-01-18 22:55:47

+0

謝謝你的回答。我其實不想使用悲觀鎖定,因爲它會成爲性能殺手。我認爲這是一個樂觀鎖定的經典用例,但我只需要爲該最終用例做好準備 – Ittai 2012-01-19 11:04:16