Spring Data JDBC參考文件

Adobe國際認證發表於2021-10-08

原標題:Spring認證|Spring Data JDBC參考文件(內容來源:Spring中國教育管理中心)

Spring Data JDBC參考文件

9. JDBC 儲存庫

本章指出了 JDBC 儲存庫支援的特殊性。這建立在使用 Spring Data Repositories 中解釋的核心儲存庫支援之上。您應該對那裡解釋的基本概念有充分的瞭解。

9.1. 為什麼選擇 Spring Data JDBC?

Java 世界中關聯式資料庫的主要持久化 API 肯定是 JPA,它有自己的 Spring Data 模組。為什麼還有一個?

JPA 做了很多事情來幫助開發人員。除其他外,它跟蹤對實體的更改。它為你做延遲載入。它使您可以將廣泛的物件構造對映到同樣廣泛的資料庫設計。

這很棒,讓很多事情變得非常簡單。只需看一下基本的 JPA 教程。但是,對於 JPA 為什麼要做某件事,這常常讓人感到困惑。此外,概念上非常簡單的事情在 JPA 中變得相當困難。

Spring Data JDBC 旨在通過採用以下設計決策在概念上更簡單:

如果您載入一個實體,SQL 語句就會執行。完成此操作後,您將擁有一個完全載入的實體。沒有進行延遲載入或快取。

如果您儲存一個實體,它將被儲存。如果您不這樣做,則不會。沒有髒跟蹤,也沒有會話。

有一個關於如何將實體對映到表的簡單模型。它可能只適用於相當簡單的情況。如果您不喜歡那樣,您應該編寫自己的策略。Spring Data JDBC 僅對使用註釋自定義策略提供非常有限的支援。

9.2. 領域驅動設計和關聯式資料庫。

所有 Spring Data 模組都受到領域驅動設計中“儲存庫”、“聚合”和“聚合根”概念的啟發。這些對於 Spring Data JDBC 來說可能更為重要,因為在某種程度上,它們與使用關聯式資料庫時的常規做法背道而馳。

聚合是一組實體,可以保證在對其進行原子更改之間保持一致。一個經典的例子是Orderwith OrderItems。上的屬性Order(例如,numberOfItems與 的實際數量OrderItems一致)在進行更改時保持一致。

跨聚合的引用不能保證在任何時候都是一致的。他們保證最終會變得一致。

每個聚合都有一個聚合根,它是聚合的實體之一。聚合僅通過該聚合根上的方法進行操作。這些是前面提到的原子變化。

儲存庫是對持久儲存的抽象,它看起來像是某種型別的所有聚合的集合。對於 Spring Data 一般而言,這意味著您希望Repository每個聚合根都有一個。此外,對於 Spring Data JDBC,這意味著可從聚合根訪問的所有實體都被視為該聚合根的一部分。Spring Data JDBC 假定只有聚合具有指向儲存聚合的非根實體的表的外來鍵,並且沒有其他實體指向非根實體。

在當前的實現中,從聚合根引用的實體被 Spring Data JDBC 刪除並重新建立。

您可以使用與您的工作和設計資料庫的風格相匹配的實現來覆蓋儲存庫方法。

9.3. 入門

引導設定工作環境的一種簡單方法是在STS 中或從Spring Initializr建立一個基於 Spring 的專案。

首先,您需要設定一個正在執行的資料庫伺服器。請參閱您的供應商文件,瞭解如何為 JDBC 訪問配置資料庫。

在 STS 中建立 Spring 專案:

轉到 File → New → Spring Template Project → Simple Spring Utility Project,然後在出現提示時按 Yes。然後輸入專案和包名稱,例如org.spring.jdbc.example.

將以下內容新增到pom.xmlfilesdependencies元素:

org.springframework.data

spring-data-jdbc

2.2.5

將 pom.xml 中 Spring 的版本改為

將 Maven 的 Spring Milestone 儲存庫的以下位置新增到您pom.xml的元素中,使其與您的元素處於同一級別:

spring-milestone

Spring Maven MILESTONE Repository

儲存庫也可在此處瀏覽。

Spring Data JDBC參考文件

9.4. 示例庫

有一個包含多個示例的GitHub 儲存庫,您可以下載並試用這些示例,以瞭解該庫的工作原理。

9.5. 基於註解的配置

Spring Data JDBC 儲存庫支援可以通過 Java 配置的註解來啟用,如下例所示:

示例 54.使用 Java 配置的 Spring Data JDBC 儲存庫

Spring Data JDBC參考文件

@Configuration

@EnableJdbcRepositories

class ApplicationConfig extends AbstractJdbcConfiguration {

@Bean

public DataSource dataSource() {

EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();

return builder.setType(EmbeddedDatabaseType.HSQL).build();

}

@Bean

NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource) {

return new NamedParameterJdbcTemplate(dataSource);

}

@Bean

TransactionManager transactionManager(DataSource dataSource) {

return new DataSourceTransactionManager(dataSource);

}

}

@EnableJdbcRepositories 為派生自的介面建立實現 Repository

AbstractJdbcConfiguration 提供 Spring Data JDBC 所需的各種預設 bean

建立DataSource到資料庫的連線。這是以下兩個 bean 方法所必需的。

建立
NamedParameterJdbcOperationsSpring Data JDBC 用來訪問資料庫的 。

Spring Data JDBC 利用 Spring JDBC 提供的事務管理。

在前面的例子中的配置類,通過使用設定了一個嵌入式HSQL資料庫EmbeddedDatabaseBuilder的API spring-jdbc。該DataSource則用來建立
NamedParameterJdbcOperations和TransactionManager。我們最終通過使用@EnableJdbcRepositories. 如果沒有配置基礎包,則使用配置類所在的包。擴充套件AbstractJdbcConfiguration確保各種 bean 得到註冊。覆蓋其方法可用於自定義設定(見下文)。

使用 Spring Boot 可以進一步簡化此配置。DataSource一旦啟動器
spring-boot-starter-data-jdbc包含在依賴項中,使用 Spring Boot就足夠了。其他一切都由 Spring Boot 完成。

在此設定中,您可能需要自定義幾項內容。

9.5.1. 方言

Spring Data JDBC 使用介面的實現Dialect來封裝特定於資料庫或其 JDBC 驅動程式的行為。預設情況下,會AbstractJdbcConfiguration嘗試確定正在使用的資料庫並註冊正確的Dialect. 這種行為可以通過覆蓋來改變jdbcDialect(
NamedParameterJdbcOperations)。

如果您使用的資料庫沒有可用的方言,那麼您的應用程式將無法啟動。在這種情況下,您必須要求您的供應商提供Dialect實現。或者,您可以:

實施您自己的Dialect.

實現一個JdbcDialectProvider返回Dialect.

通過spring.factories在下面建立資源來註冊提供者META-INF並通過新增一行來執行註冊

org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=

9.6. 持久實體

可以使用該CrudRepository.save(…)方法執行儲存聚合。如果聚合是新的,這將導致聚合根的插入,然後是所有直接或間接引用的實體的插入語句。

如果聚合根不是新的,則所有引用的實體都會被刪除,聚合根會更新,並且所有引用的實體都會再次插入。請注意,例項是否為新例項是例項狀態的一部分。

這種方法有一些明顯的缺點。如果實際更改的引用實體很少,則刪除和插入是浪費。雖然這個過程可以而且很可能會得到改進,但 Spring Data JDBC 可以提供的內容存在某些限制。它不知道聚合的先前狀態。因此,任何更新過程始終必須採用它在資料庫中找到的任何內容,並確保將其轉換為傳遞給 save 方法的實體的任何狀態。

9.6.1. 物件對映基礎

本節涵蓋 Spring Data 物件對映、物件建立、欄位和屬性訪問、可變性和不變性的基礎知識。請注意,本節僅適用於不使用底層資料儲存(如 JPA)的物件對映的 Spring Data 模組。此外,請務必查閱特定於儲存的部分以獲取特定於儲存的物件對映,例如索引、自定義列或欄位名稱等。

Spring Data 物件對映的核心職責是建立域物件的例項並將儲存本機資料結構對映到這些例項上。這意味著我們需要兩個基本步驟:

使用公開的建構函式之一建立例項。

例項填充以實現所有公開的屬性。

物件建立

Spring Data 會自動嘗試檢測要用於具體化該型別物件的持久實體的建構函式。解析演算法的工作原理如下:

如果只有一個建構函式,則使用它。

如果有多個建構函式並且只有一個用 註釋@PersistenceConstructor,則使用它。

如果存在無引數建構函式,則使用它。其他建構函式將被忽略。

值解析假定建構函式引數名稱與實體的屬性名稱匹配,即解析將被執行,就像要填充屬性一樣,包括對映中的所有自定義(不同的資料儲存列或欄位名稱等)。這還需要類檔案中可用的引數名稱資訊或@ConstructorProperties建構函式中存在的註釋。

可以通過使用@Value特定於商店的 SpEL 表示式使用 Spring Framework 的值註釋來自定義值解析。有關更多詳細資訊,請參閱有關商店特定對映的部分。

物件建立內部

為了避免反射的開銷,Spring Data 物件建立預設使用執行時生成的工廠類,它會直接呼叫域類建構函式。即對於此示例型別:

Spring Data JDBC參考文件

class Person {

Person(String firstname, String lastname) { … }

}

我們將在執行時建立一個語義上等同於這個的工廠類:

class PersonObjectInstantiator implements ObjectInstantiator {

Object newInstance(Object... args) {

return new Person((String) args[0], (String) args[1]);

}

}

這使我們比反射提高了大約 10% 的效能。對於有資格進行此類優化的域類,它需要遵守一組約束:

它不能是私人課程

它不能是非靜態內部類

它不能是 CGLib 代理類

Spring Data 使用的建構函式不能是私有的

如果這些條件中的任何一個匹配,Spring Data 將通過反射回退到實體例項化。

物業人口

一旦建立了實體的例項,Spring Data 就會填充該類的所有剩餘持久屬性。除非實體的建構函式已經填充(即通過其建構函式引數列表消耗),識別符號屬性將首先填充以允許迴圈物件引用的解析。之後,所有尚未由建構函式填充的非瞬態屬性都在實體例項上設定。為此,我們使用以下演算法:

如果屬性是不可變的但公開了一個with…方法(見下文),我們使用該with…方法建立一個具有新屬性值的新實體例項。

如果定義了屬性訪問(即通過 getter 和 setter 訪問),我們將呼叫 setter 方法。

如果屬性是可變的,我們直接設定欄位。

如果屬性是不可變的,我們將使用永續性操作(請參閱物件建立)使用的建構函式來建立例項的副本。

預設情況下,我們直接設定欄位值。

財產人口內部

與我們在物件構造中的優化類似,我們也使用 Spring Data 執行時生成的訪問器類與實體例項進行互動。

class Person {

private final Long id;

private String firstname;

private @AccessType(Type.PROPERTY) String lastname;

Person() {

this.id = null;

}

Person(Long id, String firstname, String lastname) {

// Field assignments

}

Person withId(Long id) {

return new Person(id, this.firstname, this.lastame);

}

void setLastname(String lastname) {

this.lastname = lastname;

}

}

Spring Data JDBC參考文件

示例 55. 生成的屬性訪問器

class PersonPropertyAccessor implements PersistentPropertyAccessor {

private static final MethodHandle firstname;

private Person person;

public void setProperty(PersistentProperty property, Object value) {

String name = property.getName();

if ("firstname".equals(name)) {

firstname.invoke(person, (String) value);

} else if ("id".equals(name)) {

this.person = person.withId((Long) value);

} else if ("lastname".equals(name)) {

this.person.setLastname((String) value);

}

}

}

Spring Data JDBC參考文件

PropertyAccessor 持有底層物件的可變例項。這是為了啟用其他不可變屬性的突變。

預設情況下,Spring Data 使用欄位訪問來讀取和寫入屬性值。根據private欄位的可見性規則,MethodHandles用於與欄位進行互動。

該類公開了一個withId(…)用於設定識別符號的方法,例如,當一個例項插入到資料儲存中並生成一個識別符號時。呼叫withId(…)建立一個新Person物件。所有後續突變都將發生在新例項中,而前一個例項保持不變。

使用屬性訪問允許直接方法呼叫而不使用MethodHandles.

這使我們比反射提高了大約 25% 的效能。對於有資格進行此類優化的域類,它需要遵守一組約束:

型別不得位於預設值或java包下。

型別及其建構函式必須是 public

屬於內部類的型別必須是static.

使用的 Java 執行時必須允許在原始ClassLoader. Java 9 和更新版本施加了某些限制。

預設情況下,Spring Data 會嘗試使用生成的屬性訪問器,並在檢測到限制時回退到基於反射的訪問器。

內容提示:本文(Spring Data JDBC參考文件)未完待續...... #spring認證# #Spring# #程式設計師#


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69981720/viewspace-2794910/,如需轉載,請註明出處,否則將追究法律責任。

相關文章