持久化實體
可以使用 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 列使用了自增(auto-increment)時,生成的值將在實體插入資料庫後設置到實體中。
當實體是新的且識別符號值預設為其初始值時,Spring Data 不會嘗試插入識別符號列的值。對於原始型別,初始值是 0
;如果識別符號屬性使用 Long
等數字包裝型別,則初始值是 null
。
實體狀態檢測詳細解釋瞭如何檢測實體是否是新的,或者是否預期已存在於資料庫中。
一個重要的約束是,實體儲存後,它就不再是新的了。請注意,實體是否為新實體是實體狀態的一部分。對於自增列,這是自動發生的,因為 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 Repositories 實現自定義方法的部分,讓您可以使用 JdbcAggregateTemplate
來自定義和擴充套件您的 Repositories。
持久化
JdbcAggregateTemplate
提供了三種用於持久化實體的方法:save
、insert
和 update
。每種方法都有兩種形式:一種操作單個聚合(名稱如上所述),另一種則帶有 All
字尾,操作一個 Iterable
。
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
運算子為可變引數建立一個條件。 -
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
運算子為可變引數建立一個條件。 -
Criteria
notIn(Collection<?> collection)
: 使用NOT IN
運算子為集合建立一個條件。
樂觀鎖
Spring Data 透過在聚合根上使用標註了 @Version
註解的數字屬性來支援樂觀鎖。每當 Spring Data 儲存帶有此版本屬性的聚合時,會發生兩件事:
-
聚合根的 update 語句將包含一個 where 子句,用於檢查資料庫中儲存的版本是否確實未改變。
-
如果不是這種情況,將丟擲
OptimisticLockingFailureException
。
此外,版本屬性在實體和資料庫中都會增加,以便併發操作會注意到此變化,並在適用時丟擲 OptimisticLockingFailureException
,如上所述。
這個過程也適用於插入新的聚合,其中 null
或 0
版本表示新例項,之後增加的版本會將例項標記為不再是新的,這使得它非常適合那些在物件構造期間生成 ID 的情況,例如使用 UUID 時。
在刪除過程中,版本檢查也適用,但版本不會增加。