持久化實體
儲存聚合可以透過 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 方法,不適用於派生查詢和註解查詢。計劃將來取消此限制。 -
需要透過呼叫
setSingleQueryLoadingEnabled(true)在JdbcMappingContext中啟用單查詢載入。
-
如果任何條件不滿足,Spring Data JDBC 將退回預設的聚合載入方法。
| 單查詢載入被認為是實驗性的。我們非常感謝您提供關於其使用情況的反饋。 |
| 雖然單查詢載入可以縮寫為 SQL,但我們強烈不建議這樣做,因為幾乎肯定會與結構化查詢語言混淆。 |
ID 生成
Spring Data 使用識別符號屬性來標識實體。也就是說,查詢這些實體或建立針對特定行的語句。實體的 ID 必須使用 Spring Data 的 @Id 註解進行標註。
當您的資料庫的 ID 列具有自增功能時,生成的值在實體插入資料庫後會被設定到實體中。
如果您還用 @Sequence 註解識別符號屬性,並且底層 Dialect 支援序列,則將使用資料庫序列來獲取 ID 的值。
否則,當實體是新的且識別符號值預設為其初始值時,Spring Data 不會嘗試插入識別符號列的值。也就是說,對於基本型別是 0,如果識別符號屬性使用數字包裝型別(例如 Long),則為 null。
實體狀態檢測詳細解釋了檢測實體是新的還是預期存在於資料庫中的策略。
一個重要的約束是,儲存實體後,實體不得再是新的。請注意,實體是否是新的,是實體狀態的一部分。對於自增列,這會自動發生,因為 ID 會由 Spring Data 使用 ID 列中的值進行設定。
模板 API
作為儲存庫的替代方案,Spring Data JDBC 提供 JdbcAggregateTemplate,作為在關係資料庫中載入和持久化實體的更直接方式。在很大程度上,儲存庫使用 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。每種方法都有兩種形式:對單個聚合進行操作,名稱與上述完全相同;以及帶有 All 字尾,對 Iterable 進行操作。
save 與儲存庫中同名方法的功能相同。
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 運算子
-
Criteriaand(String column):將一個帶有指定property的鏈式Criteria新增到當前Criteria並返回新建立的那個。 -
Criteriaor(String column):將一個帶有指定property的鏈式Criteria新增到當前Criteria並返回新建立的那個。 -
CriteriagreaterThan(Object o):使用>運算子建立條件。 -
CriteriagreaterThanOrEquals(Object o):使用>=運算子建立條件。 -
Criteriain(Object… o):使用IN運算子為可變引數建立條件。 -
Criteriain(Collection<?> collection):使用IN運算子透過集合建立條件。 -
Criteriais(Object o):使用列匹配(property = value)建立條件。 -
CriteriaisNull():使用IS NULL運算子建立條件。 -
CriteriaisNotNull():使用IS NOT NULL運算子建立條件。 -
CriterialessThan(Object o):使用<運算子建立條件。 -
CriterialessThanOrEquals(Object o):使用⇐運算子建立條件。 -
Criterialike(Object o):使用LIKE運算子建立條件,不進行跳脫字元處理。 -
Criterianot(Object o):使用!=運算子建立條件。 -
CriterianotIn(Object… o):使用NOT IN運算子為可變引數建立條件。 -
CriterianotIn(Collection<?> collection):使用NOT IN運算子透過集合建立條件。
樂觀鎖定
Spring Data 透過聚合根上用 @Version 註解的數字屬性支援樂觀鎖定。每當 Spring Data 儲存帶有此版本屬性的聚合時,會發生兩件事:
-
聚合根的更新語句將包含一個 where 子句,檢查資料庫中儲存的版本是否確實未更改。
-
如果不是這種情況,將丟擲
OptimisticLockingFailureException。
此外,版本屬性在實體和資料庫中都會增加,因此併發操作會注意到更改,並在適用時(如上所述)丟擲 OptimisticLockingFailureException。
這個過程也適用於插入新的聚合,其中 null 或 0 版本表示一個新例項,隨後的增加例項將例項標記為不再是新的,這使得它在物件構建期間生成 ID 的情況下(例如使用 UUID 時)工作得非常好。
在刪除期間,版本檢查也適用,但版本不會增加。