領先一步
VMware 提供培訓和認證,以加速您的進展。
了解更多Spring Data 2021.0,代號 Pascal,是遵循新的六個月節奏發布的第二個版本。 它對許多現有介面和程式設計模型進行了改進。 這篇部落格文章說明了以下主題
為 Repositories 和 CassandraTemplate
啟用 Cassandra Prepared Statements。
Repository projections & Apache Geode 的函數執行。
CrudRepository
和 ReactiveCrudRepository
引入 deleteAllById
自成立以來,CrudRepository
定義了一種方法,可以通過實體識別碼來刪除個別實體。 在 1.x 開發系列中,delete(…)
方法被多載以接受各種引數類型,遵循 delete(ID id)
和 delete(Iterable<? extends T> entities)
。
在 Spring Data 2.0 版本中,我們重新命名了 CrudRepository
方法,以表達特定方法將接受哪個引數。 重新命名後,這些方法看起來像 deleteById(ID id)
和 deleteAll(Iterable<? extends T> entities)
。 精簡的命名慣例允許引入一種刪除方法,該方法通過實體識別碼刪除實體。 從此版本開始,CrudRepository
和 ReactiveCrudRepository
都定義了 deleteAllById(Iterable<? extends ID> ids)
以刪除多個實體。
根據實際的儲存模組,如果資料儲存支援,這可能是一個批次刪除(按查詢刪除)。 例如,JPA 實作仍然首先實現所有實體以立即刪除它們,以便仍然為即將刪除的實例調用生命週期回調。 在 JpaRepoository
中引入了一個額外的 deleteAllByIdInBatch(…)
,以使用批次查詢提供更快的執行變體。
Java Flight Recorder (JFR) 是一種工具,用於收集、診斷和分析有關正在執行的 Java 應用程式的資料。 它與 Java 執行時緊密集成,允許在生產環境中以低額外負荷收集事件。
Spring Data 儲存庫通常在應用程式啟動時引導,因此它們自然會影響啟動時間。 Pascal 版本引入了與 Spring Framework 對捕獲啟動事件的支持的集成,該支持自 5.3 版本開始可用。 通過啟用 JFR 記錄,您可以收集和分析以下儲存庫啟動事件
對於每個啟用的 Spring Data 模組 (@Enable…Repositories
)
spring.data.repository.scanning
:儲存庫介面掃描對於每個儲存庫
spring.data.repository.init
:儲存庫初始化
spring.data.repository.metadata
:元資料檢索
spring.data.repository.composition
:儲存庫組成的組裝
spring.data.repository.target
:儲存庫目標建立
spring.data.repository.proxy
:儲存庫代理建立
spring.data.repository.postprocessors
:儲存庫代理後處理
您可以通過在所有 Java 9 或更新的執行時或 Java 8 更新 262 或更高版本上使用 java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar …
啟動您的應用程式來啟用 JFR 記錄。
KProperty
和 KPropertyPath
來進行屬性路徑呈現Spring Data Kotlin 集成是我們特定於語言的擴展的“語法糖”增強的強大驅動因素。 Kotlin 允許將單個屬性引用為屬性引用(data class Book(val title: String)
,Book::title
)。 它們是重構安全和編譯安全的,因為 Kotlin 編譯器會立即拒絕無效的引用。 現代 IDE 支援在重新命名屬性時考慮屬性引用,從而消除了純字串中殘留引用的風險。
Spring Data MongoDB 2.2 引入了對其 Criteria
API 的 KProperty
和 KPropertyPath
的支援
屬性的經典用法
val classic = Criteria("title").isEqualTo("Moby-Dick")
.and("price").lt(950)
val typed = (Book::title isEqualTo "Moby-Dick")
.and(Book::price).lt(950)
Spring Data Commons 2.5 將 KPropertyPath
提升為 Spring Data 中的頂級概念。 為了不要求擴展或更改接受屬性路徑的所有方法,您可以通過呈現屬性路徑將 KPropertyPath
與現有的 Spring Data 實用程式一起使用
// KPropertyPath variant
Sort.by((Book::author / Author::name).toDotPath())
// String-path equivalent
Sort.by("author.name")
// KPropertyPath variant
ExampleMatcher.matching()
.withMatcher((Book::author / Author::name).toDotPath(), contains())
// String-path equivalent
ExampleMatcher.matching()
.withMatcher("author.name", contains())
此發布系列不再隨附 Spring Data for Apache Solr。 在2020 年棄用 Spring Data Solr之後,團隊決定停止維護 Solr 模組。 但是,我們將繼續發布維護的 4.2 和 4.3 開發系列的服務版本,直到它們分別在 2021 年 5 月和 2021 年 11 月達到其生命週期終止。 展望未來,我們建議使用Spring Data Elasticsearch 作為全文本搜尋安排的 Spring Data 模組的首選。 Spring Data Elasticsearch 是一個積極維護的社群模組。
QueryByExample
Query by Example 是一種使用者友好的查詢技術,具有簡單的介面。 它允許動態查詢建立,並且不需要編寫包含欄位名稱的查詢。 事實上,Query by Example 根本不需要您使用 SQL 編寫查詢。 它適用於多個 Spring Data 模組。 從 Spring Data R2DBC 1.3 開始,您可以通過 Spring Data R2DBC 的 ReactiveQueryByExampleExecutor
實作,使用範例查詢關聯式資料。
PersonRepository people = …;
DatabaseClient client = …;
var skyler = new Person(null, "Skyler", "White", 45);
var walter = new Person(null, "Walter", "White", 50);
var flynn = new Person(null, "Walter Jr. (Flynn)", "White", 17);
var marie = new Person(null, "Marie", "Schrader", 38);
var hank = new Person(null, "Hank", "Schrader", 43);
var example = Example.of(new Person(null, null, "White", null));
people.count(example).as(StepVerifier::create)
.expectNext(3L)
.verifyComplete();
var example = Example.of(new Person(null, "Walter", "WHITE", null), matching()
.withIgnorePaths("age"). //
.withMatcher("firstname", startsWith())
.withMatcher("lastname", ignoreCase()));
people.findAll(example).collectList()
.as(StepVerifier::create)
.consumeNextWith(actual -> {
assertThat(actual).containsExactlyInAnyOrder(flynn, walter);
})
.verifyComplete();
除了其他改進之外,您還可以將 Spring Framework 5.3.6 和 Spring Data R2DBC 1.3 與 Oracle 的 oracle-r2dbc
(com.oracle.database.r2dbc:oracle-r2dbc
) 驅動程式一起使用。 通過使用 Oracle ConnectionFactory
建立 DatabaseClient
或 R2dbcEntityTemplate
選擇適當的綁定標記策略和方言。
CassandraTemplate
啟用 Cassandra Prepared StatementsSpring Data for Apache Cassandra 盡可能地支援 Cassandra 特有的功能。自 2.0 版本進行重大改寫以來,我們引入了 CachedPreparedStatementCreator
,用於在 CqlTemplate
層級上快取 prepared statement,這使得可以使用 plain CQL 來使用 prepared statement。
在這個版本中,我們將 prepared statement 的支援引入到 CassandraTemplate
及其反應式 (reactive) 和非同步 (asynchronous) 變體。實際上,prepared statement 預設是啟用的。CqlTemplate
和 CassandraTemplate
之間的主要區別在於抽象層級和 CQL 語句建立的責任。CqlTemplate
需要 CQL 作為輸入。CassandraTemplate
使用實體 (entity) 作為輸入,並根據應該使用該實體執行的實際操作來產生 CQL 語句。
提供 prepared statement 功能的變更帶來了一些發出查詢時的變更
使用 StatementBuilder
時,參數是按索引綁定的。當為實體相關操作建立 CQL 查詢時,所有配置都會使用 StatementBuilder
。
當按索引繫結參數時,檢查 SimpleStatement
會在它的 CQL 中呈現參數繫結標記。CqlTemplate
的 CQL 日誌也會受到此變更的影響:記錄的 CQL 現在包含 ?
而不是字面值。
需要這些變更才能允許對參數化語句進行語句準備 (statement preparation)。要執行的語句會先進行準備。然後,在第二個步驟中,它會與其實際參數繫結,然後傳送到伺服器以供執行。
Cassandra 的 Java Driver 會追蹤 prepared statement 的快取,因此在 bean 設定方面不需要任何工作。通常,您應該會體驗到更好的查詢效能。此外,請記住,prepared statement 快取需要額外的記憶體來追蹤 prepared statement。
您可以停用 CassandraTemplate
及其反應式 (reactive) 和非同步 (asynchronous) 變體上的 prepared statement 使用
var template = new CassandraTemplate(session);
template.setUsePreparedStatements(false);
您可以在 Spring Data for Apache Cassandra 參考文件 中找到更多詳細資訊。
Value 物件和 record 類型有助於我們建立具有最大表達能力的結構清晰的網域模型。然而,持久化這些精心製作的模型不一定會產生結構良好的資料庫文件。在 Java 或 Kotlin 中看起來不錯的東西可能會導致屬性名稱的意外重複,以及在 MongoDB 原生 Document 格式中的深層巢狀結構,該格式將實體嵌入其父結構中。考慮以下簡單的程式碼片段及其表示
class User {
private String id;
private Email email;
// …
}
record Email (String email) {}
{
"_id" : "9708-ac32-beb0",
"email" : {
"email" : "[email protected]"
},
// …
}
雖然這有效,但顯然不是文件儲存的慣用表示法,而這正是 @Unwrapped
發揮作用的地方。該註解可讓您將屬性扁平化(解包)到其父項中
class User {
private String id;
@Unwrapped(onEmpty = OnEmpty.USE_NULL)
private Email email;
// …
}
@Unwrapped
強迫您決定如何處理不存在的值,方法是選擇 onEmpty
行為(record 表示的任何欄位都不存在)。對於那些喜歡不太冗長的註解的人,可以隨意使用 @Unwrapped.Nullable
作為替代方案,或使用 @Unwrapped
作為 meta 註解來建立您自己的註解。無論如何,產生的文件看起來更具吸引力
{
"_id" : "9708-ac32-beb0",
"email" : "[email protected]",
// …
}
Repositories 和 MongoTemplate
都能夠處理已解包的屬性。有關更多資訊,請參閱參考文件。另請查看 @Unwrapped
的範例。
Spring Data repository 抽象一直是專案中的核心概念。它是一個架構概念的程式設計模型,該概念在網域驅動設計 (DDD) 中被稱為:repository 抽象了一個 aggregate 的集合。實際上,Spring Framework 本身與源自 DDD 的其他一些抽象(例如服務)保持一致,並提供註解以在使用者程式碼中表達它們。但是,使用者通常不喜歡使用框架特定的註解和抽象來表達這些概念。
jMolecules 專案專注於提供基於註解和類型的抽象,不同的技術架構概念可以與之整合。它本質上顛倒了這種關係:使用者程式碼僅依賴 jMolecules 註解和介面,然後 技術整合 — 在第二步中 — 可以從 廣泛的 jMolecules 整合庫或框架本身提供。
jMolecules 的網域驅動設計模組中的核心抽象之一是 Association
介面。它被類型化為 AggregateRoot
及其 Identifier
,並用於網域模型中以強類型的方式表達與 aggregate 的關係
class Order implements AggregateRoot<Order, OrderIdentifier> {
OrderIdentifier id;
Association<Customer, CustomerIdentifier> customer;
}
在此模型中,Order
和 Customer
都是 aggregate,並且兩者之間的關聯是透過 jMolecules Association
類型顯式映射的。Spring Data 2021.0.0 提供了對 Association
的映射支援。它們被正確地檢測為 Spring Data 關聯,並使用支援實例的識別碼進行轉換。
若要透明地啟用對這些抽象的支援,請將 org.jmolecules.integrations:jmolecules-spring
新增到您的類別路徑中。Spring Data 的映射基礎架構會檢測到這一點,並自動在我們物件映射設施的轉換部分中註冊必要的轉換器。
JPA 也提供了對 Association
實例的支援。但是,在這種情況下,Spring Data 不提供實際的轉換,而是透過與 jMolecules 本身提供的 AttributeConverter
實作整合來提供。使用 其 ByteBuddy 擴充,您可以產生必要的 AttributeConverter
實作和註解配置。
jMolecules 的 Identifier
介面鼓勵為 aggregate 使用專用的識別碼類型,如先前範例中使用的 OrderIdentifier
和 CustomerIdentifier
類型。在序列化 Association
時,我們現在實際上必須透過依次呼叫 Association.getId()
和 Identifier.getId()
將實例轉換為 CustomerIdentifier
,才能取得實際要持久化的值。若要實現關聯,我們必須取得原始持久化的值,透過使用名為 ….of(…)
的公開靜態工廠方法建立 CustomerIdentifier
實例,並最終再次呼叫 Association.of(…)
。
所有這些轉換步驟都在 jmolecules-integrations
中實作,並由 Spring Data 透明地新增到 Spring ConversionService
中,供框架使用。假設 OrderIdentifier
由 UUID
的 String
表示支援,這也意味著 Spring Data 的 DomainClassConverter
能夠自動將完全實現的 aggregate 實例繫結到 Spring MVC 控制器方法
@RestController
class MyController {
@GetMapping("/orders/{id}")
HttpEntity<?> getOrders(@PathVariable("id") Order order) { /* … */ }
}
在此範例中,對 /orders/462a692d-…
的 GET 請求會先使用 jMolecules 轉換器自動將 462a692d-…
轉換為 OrderIdentifier
,然後使用為 Order
宣告的 repository 來查閱 aggregate 實例。雖然 一般機制 在 Spring Data 中已經可用很長一段時間,但 2021.0.0 版本為 jMolecules Identifier
實作新增了必要的額外整合。
先前提及的 jMolecules Converter
實作也用於 Spring Data REST 需要取得彙總識別符並將其轉換為 URI 的所有位置。該模組還附帶一個新的 Jackson 反序列化器,允許透過正確反序列化 URI,將 Spring Data REST 管理的彙總實例繫結到 DTO 中。假設您有一個由 Spring Data REST 管理並透過 /orders/…
公開的 Order
,以及一個看起來像這樣的客戶端控制器配置
@BasePathAwareController
class MyCustomController {
@PostMapping("/orders")
HttpEntity<?> postOrder(@RequestBody MyDto payload) {
/* Process submission */
}
}
@Data
class MyDto {
List<Order> orders;
}
現在也假設為請求提交以下酬載
{
"orders" : [
"…/orders/462a692d-…"
]
}
儘管 MyDto
是一個普通的資料傳輸物件,但 payload
實例包含由 462a692d-…
識別的彙總實例,作為 orders
連結的元素。