持久化實體
儲存聚合可以使用 CrudRepository.save(…)
方法來執行。如果聚合是新的,這會導致對聚合根進行插入,然後對所有直接或間接引用的實體執行插入語句。
如果聚合根不是新的,所有引用的實體都會被刪除,聚合根會被更新,然後所有引用的實體會再次被插入。請注意,實例是否為新的,是實例狀態的一部分。
這種方法有一些明顯的缺點。如果只有少數引用的實體實際上被更改了,刪除和插入是很浪費的。雖然這個過程可以而且可能會被改進,但 Spring Data JDBC 可以提供的東西有一定的限制。它不知道聚合的先前狀態。因此,任何更新過程都必須始終接受在資料庫中找到的任何內容,並確保將其轉換為傳遞給 save 方法的實體狀態。 |
另請參閱 實體狀態偵測 以取得更多詳細資訊。
載入聚合
Spring Data JDBC 提供兩種載入聚合的方式
-
傳統方式,也是在 3.2 版本之前的唯一方式,非常簡單:每個查詢都會載入聚合根,無論查詢是基於
CrudRepository
方法、衍生查詢還是註解查詢。如果聚合根引用了其他實體,這些實體將使用單獨的語句載入。 -
Spring Data JDBC 3.2 允許使用單一查詢載入。使用此功能,可以使用單一 SQL 查詢完全載入任意數量的聚合。這應該會顯著提高效率,特別是對於由許多實體組成的複雜聚合。
目前,單一查詢載入在不同方面受到限制
-
聚合不得具有巢狀集合,包括
Map
。計劃在未來移除此限制。 -
聚合不得使用
AggregateReference
或嵌入式實體。計劃在未來移除此限制。 -
資料庫方言必須支援它。在 Spring Data JDBC 提供的方言中,除了 H2 和 HSQL 之外,所有方言都支援此功能。H2 和 HSQL 不支援分析函數(又稱視窗函數)。
-
它僅適用於
CrudRepository
中的 find 方法,不適用於衍生查詢,也不適用於註解查詢。計劃在未來移除此限制。 -
單一查詢載入需要在
JdbcMappingContext
中啟用,方法是呼叫setSingleQueryLoadingEnabled(true)
-
如果任何條件未滿足,Spring Data JDBC 將退回預設的聚合載入方法。
單一查詢載入被認為是實驗性的。我們感謝您關於它如何為您工作的回饋。 |
雖然單一查詢載入可以縮寫為 SQL,但我們強烈不建議這樣做,因為與結構化查詢語言混淆幾乎是必然的。 |
ID 產生
Spring Data 使用識別符屬性來識別實體。實體的 ID 必須使用 Spring Data 的 @Id
註解來註解。
當您的資料庫的 ID 欄位具有自動遞增欄位時,產生的值會在插入到資料庫後設定到實體中。
當實體是新的且識別符值預設為其初始值時,Spring Data 不會嘗試插入識別符欄位的值。對於原始類型,初始值為 0
,如果識別符屬性使用數值包裝類型(例如 Long
),則初始值為 null
。
實體狀態偵測 詳細說明了偵測實體是否為新的,或是否預期存在於您的資料庫中的策略。
一個重要的限制是,在儲存實體後,該實體不得再是新的。請注意,實體是否為新的,是實體狀態的一部分。使用自動遞增欄位,這會自動發生,因為 ID 會由 Spring Data 設定為來自 ID 欄位的值。
Template API
作為 Repository 的替代方案,Spring Data JDBC 提供了 JdbcAggregateTemplate
,作為在關聯式資料庫中載入和持久化實體的更直接方法。在很大程度上,Repository 使用 JdbcAggregateTemplate
來實作其功能。
本節僅重點介紹 JdbcAggregateTemplate
中最有趣的部分。如需更完整的概述,請參閱 JdbcAggregateTemplate
的 JavaDoc。
存取 JdbcAggregateTemplate
JdbcAggregateTemplate
旨在作為 Spring bean 使用。如果您已設定您的應用程式以包含 Spring Data JDBC,您可以在任何 Spring bean 中設定對 JdbcAggregateTemplate
的依賴性,而 Spring Framework 會注入一個正確設定的實例。
這包括您用來為您的 Spring Data Repository 實作自訂方法的片段,讓您可以使用 JdbcAggregateTemplate
來客製化和擴充您的 Repository。
持久化
JdbcAggregateTemplate
提供三種類型的持久化實體方法:save
、insert
和 update
。每種類型都有兩種形式:對單一聚合進行操作(名稱與上述完全相同),以及對 Iterable
進行操作的帶有 All
後綴的操作。
save
的作用與 Repository 中同名的方法相同。
insert
和 update
跳過測試實體是否為新的步驟,並根據它們的名稱指示,假設為新的或現有的聚合。
查詢
JdbcAggregateTemplate
提供了相當多的方法來查詢聚合和聚合集合。有一種方法需要特別注意。那就是以 Query
作為引數的方法。它們允許執行以程式方式建構的查詢,如下所示
template.findOne(query(where("name").is("Gandalf")), Person.class);
由 query
方法回傳的 Query
定義了要選擇的欄位列表、where 子句(透過 CriteriaDefinition)以及 limit 和 offset 子句的規範。有關 Query
類別的詳細資訊,請參閱其 JavaDoc。
Criteria
類別,其中 where
是一個靜態成員,提供了 org.springframework.data.relational.core.query.CriteriaDefinition[] 的實作,它表示查詢的 where 子句。
Criteria 類別的方法
Criteria
類別提供以下方法,所有這些方法都對應於 SQL 運算子
-
Criteria
and(String column)
:將具有指定property
的鏈式Criteria
新增到目前的Criteria
,並回傳新建立的Criteria
。 -
Criteria
or(String column)
:將具有指定property
的鏈式Criteria
新增到目前的Criteria
,並回傳新建立的Criteria
。 -
Criteria
greaterThan(Object o)
:使用>
運算子建立條件。 -
Criteria
greaterThanOrEquals(Object o)
:使用>=
運算子建立條件。 -
Criteria
in(Object… o)
:使用IN
運算子為 varargs 引數建立條件。 -
Criteria
in(Collection<?> collection)
:使用IN
運算子為集合建立條件。 -
Criteria
is(Object o)
:使用欄位比對 (property = value
) 建立條件。 -
Criteria
isNull()
:使用IS NULL
運算子建立條件。 -
Criteria
isNotNull()
:使用IS NOT NULL
運算子建立條件。 -
Criteria
lessThan(Object o)
:使用<
運算子建立條件。 -
Criteria
lessThanOrEquals(Object o)
:使用⇐
運算子建立條件。 -
Criteria
like(Object o)
:使用LIKE
運算子建立條件,不進行跳脫字元處理。 -
Criteria
not(Object o)
:使用!=
運算子建立條件。 -
Criteria
notIn(Object… o)
:使用NOT IN
運算子為 varargs 引數建立條件。 -
Criteria
notIn(Collection<?> collection)
:使用NOT IN
運算子為集合建立條件。
樂觀鎖定
Spring Data 透過在聚合根上使用 @Version
註解的數值屬性來支援樂觀鎖定。每當 Spring Data 儲存具有此版本屬性的聚合時,會發生兩件事
-
聚合根的更新語句將包含一個 where 子句,檢查儲存在資料庫中的版本是否實際未更改。
-
如果不是這種情況,將拋出
OptimisticLockingFailureException
。
此外,版本屬性會在實體和資料庫中都增加,因此並行操作將注意到更改,並在適用的情況下拋出 OptimisticLockingFailureException
,如上所述。
此過程也適用於插入新的聚合,其中 null
或 0
版本表示新的實例,而之後增加的實例將實例標記為不再是新的,這使得此功能在 ID 在物件建構期間產生的情況下(例如在使用 UUID 時)運作良好。
在刪除期間,版本檢查也適用,但不會增加版本。