天天看點

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

原标題:Spring認證|Spring Data JPA 參考文檔六(内容來源:Spring中國教育管理中心)

5.1.4. 存儲過程

JPA 2.1 規範引入了對使用 JPA 條件查詢 API 調用存儲過程的支援。我們引入了@Procedure用于在存儲庫方法上聲明存儲過程中繼資料的注釋。

以下示例使用以下存儲過程:

Example 91. plus1inoutHSQL DB 中過程的定義。

/;

DROP procedure IF EXISTS plus1inout

CREATE procedure plus1inout (IN arg int, OUT res int)

BEGIN ATOMIC

set res = arg + 1;

END

可以通過使用NamedStoredProcedureQuery實體類型上的注釋來配置存儲過程的中繼資料。

示例 92.實體上的 StoredProcedure 中繼資料定義。

@Entity

@NamedStoredProcedureQuery(name = "User.plus1", procedureName = "plus1inout", parameters = {

@StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = Integer.class),

@StoredProcedureParameter(mode = ParameterMode.OUT, name = "res", type = Integer.class) })

public class User {}

請注意,@NamedStoredProcedureQuery存儲過程有兩個不同的名稱。 name是 JPA 使用的名稱。procedureName是存儲過程在資料庫中的名稱。

您可以通過多種方式從存儲庫方法中引用存儲過程。要調用的存儲過程可以直接使用注解的value或procedureName屬性定義@Procedure。這直接引用資料庫中的存儲過程,并忽略通過@

NamedStoredProcedureQuery.

或者,您可以将@

NamedStoredProcedureQuery.name屬性指定為@Procedure.name屬性。如果沒有value,procedureName也沒有name被配置,存儲庫方法的名稱被用作name屬性。

以下示例顯示了如何引用顯式映射的過程:

示例 93. 引用資料庫中名稱為“plus1inout”的顯式映射過程。

@Procedure("plus1inout")

Integer explicitlyNamedPlus1inout(Integer arg);

以下示例與前一個示例等效,但使用procedureName别名:

示例 94. 通過procedureName别名在資料庫中引用名為“plus1inout”的隐式映射過程。

@Procedure(procedureName = "plus1inout")

Integer callPlus1InOut(Integer arg);

以下再次等效于前兩個,但使用方法名稱而不是顯式注釋屬性。

示例 95.EntityManager使用方法名稱引用隐式映射的命名存儲過程“User.plus1” 。

@Procedure

Integer plus1inout(@Param("arg") Integer arg);

以下示例顯示如何通過引用@

NamedStoredProcedureQuery.name屬性來引用存儲過程。

示例 96.在EntityManager.

@Procedure(name = "User.plus1IO")

Integer entityAnnotatedCustomNamedProcedurePlus1IO(@Param("arg") Integer arg);

如果被調用的存儲過程有一個單出參數,則該參數可以作為方法的傳回值傳回。如果在@NamedStoredProcedureQuery注釋中指定了多個輸出參數,則這些參數可以作為 a 傳回,Map鍵是@NamedStoredProcedureQuery注釋中給出的參數名稱。

5.1.5. 規格

JPA 2 引入了一個标準 API,您可以使用它以程式設計方式建構查詢。通過編寫criteria,您可以定義域類查詢的 where 子句。再退一步,這些标準可以被視為對 JPA 标準 API 限制所描述的實體的謂詞。

Spring Data JPA 從 Eric Evans 的書“Domain Driven Design”中采用了規範的概念,遵循相同的語義并提供 API 以使用 JPA 标準 API 定義此類規範。為了支援規範,您可以使用該JpaSpecificationExecutor接口擴充您的存儲庫接口,如下所示:

public interface CustomerRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {

}

附加接口的方法可以讓您以多種方式運作規範。例如,該findAll方法傳回與規範比對的所有實體,如以下示例所示:

List<T> findAll(Specification<T> spec);

的Specification接口被定義為如下:

public interface Specification<T> {

Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,

CriteriaBuilder builder);

規範可以很容易地用于在實體之上建構一組可擴充的謂詞,然後可以組合和使用這些謂詞,JpaRepository而無需為每個需要的組合聲明查詢(方法),如以下示例所示:

示例 97. 客戶規格

public class CustomerSpecs {

public static Specification<Customer> isLongTermCustomer() {

return (root, query, builder) -> {

LocalDate date = LocalDate.now().minusYears(2);

return builder.lessThan(root.get(Customer_.createdAt), date);

};

public static Specification<Customer> hasSalesOfMoreThan(MonetaryAmount value) {

// build query here

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

該Customer_類型是使用 JPA 元模型生成器生成的元模型類型(有關示例,請參閱Hibernate 實作的文檔)。是以表達式 ,Customer_.createdAt假定Customer具有createdAt類型的屬性Date。除此之外,我們在業務需求抽象級别上表達了一些标準并建立了可執行檔案Specifications。是以用戶端可能會使用 aSpecification如下:

示例 98. 使用簡單的規範

List<Customer> customers = customerRepository.findAll(isLongTermCustomer());

為什麼不為這種資料通路建立查詢?Specification與普通的查詢聲明相比,使用單個并沒有太大的好處。當您将規範組合起來建立新Specification對象時,規範的力量會真正發揮作用。您可以通過Specification我們提供的預設方法來實作這一點,以建構類似于以下内容的表達式:

示例 99. 組合規格

MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);

List<Customer> customers = customerRepository.findAll(

isLongTermCustomer().or(hasSalesOfMoreThan(amount)));

Specification提供了一些“膠水代碼”預設方法來連結群組合Specification執行個體。這些方法讓您可以通過建立新的Specification實作并将它們與現有的實作相結合來擴充資料通路層。

5.1.6. 按示例查詢

介紹

本章介紹了 Query by Example 并解釋了如何使用它。

示例查詢 (QBE) 是一種使用者友好的查詢技術,具有簡單的界面。它允許動态建立查詢,并且不需要您編寫包含字段名稱的查詢。事實上,Query by Example 根本不需要您使用特定于商店的查詢語言編寫查詢。

用法

Query by Example API 由三部分組成:

探針:具有填充字段的域對象的實際示例。

ExampleMatcher:ExampleMatcher包含有關如何比對特定字段的詳細資訊。它可以在多個示例中重複使用。

Example: AnExample由探針和ExampleMatcher. 它用于建立查詢。

Query by Example 非常适合以下幾個用例:

使用一組靜态或動态限制查詢您的資料存儲。

頻繁重構域對象而不必擔心破壞現有查詢。

獨立于底層資料存儲 API 工作。

Query by Example 也有幾個限制:

不支援嵌套或分組的屬性限制,例如firstname = ?0 or (firstname = ?1 and lastname = ?2).

僅支援字元串的開始/包含/結束/正規表達式比對以及其他屬性類型的精确比對。

在開始使用 Query by Example 之前,您需要有一個域對象。首先,為您的存儲庫建立一個接口,如以下示例所示:

示例 100. 示例 Person 對象

public class Person {

@Id

private String id;

private String firstname;

private String lastname;

private Address address;

// … getters and setters omitted

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

前面的示例顯示了一個簡單的域對象。您可以使用它來建立Example. 預設情況下,null忽略具有值的字段,并使用商店特定的預設值比對字元串。

将屬性包含在 Query by Example 标準中是基于可空性。除非忽略屬性路徑,否則始終包含使用原始類型 ( int, double, ...)的屬性。

可以使用of工廠方法或使用ExampleMatcher. Example是不可變的。以下清單顯示了一個簡單的示例:

示例 101. 簡單示例

Person person = new Person();

person.setFirstname("Dave");

Example<Person> example = Example.of(person);

建立域對象的新執行個體。

設定要查詢的屬性。

建立Example.

您可以使用存儲庫運作示例查詢。為此,讓您的存儲庫接口擴充QueryByExampleExecutor<T>. 以下清單顯示了QueryByExampleExecutor界面的摘錄:

例 102. QueryByExampleExecutor

public interface QueryByExampleExecutor<T> {

<S extends T> S findOne(Example<S> example);

<S extends T> Iterable<S> findAll(Example<S> example);

// … more functionality omitted.

示例比對器

示例不限于預設設定。您可以使用 為字元串比對、空值處理和特定于屬性的設定指定自己的預設值ExampleMatcher,如以下示例所示:

示例 103. 具有自定義比對的示例比對器

ExampleMatcher matcher = ExampleMatcher.matching()

.withIgnorePaths("lastname")

.withIncludeNullValues()

.withStringMatcher(StringMatcher.ENDING);

Example<Person> example = Example.of(person, matcher);

設定屬性。

建立一個ExampleMatcher以期望所有值比對。即使沒有進一步的配置,它也可以在這個階段使用。

構造一個新ExampleMatcher的忽略lastname屬性路徑。

構造一個 newExampleMatcher以忽略lastname屬性路徑并包含空值。

構造一個 newExampleMatcher來忽略lastname屬性路徑,包含空值,并執行字尾字元串比對。

建立一個新的Example基于域對象和配置上ExampleMatcher。

預設情況下,ExampleMatcher期望在探測器上設定的所有值都比對。如果要獲得與任何隐式定義的謂詞比對的結果,請使用

ExampleMatcher.matchingAny().

您可以為單個屬性指定行為(例如“名字”和“姓氏”,或者對于嵌套屬性,“address.city”)。您可以使用比對選項和區分大小寫來調整它,如以下示例所示:

示例 104. 配置比對器選項

.withMatcher("firstname", endsWith())

.withMatcher("lastname", startsWith().ignoreCase());

另一種配置比對器選項的方法是使用 lambdas(在 Java 8 中引入)。這種方法建立了一個回調,要求實作者修改比對器。您不需要傳回比對器,因為配置選項儲存在比對器執行個體中。以下示例顯示了使用 lambda 的比對器:

示例 105. 使用 lambda 配置比對器選項

.withMatcher("firstname", match -> match.endsWith())

.withMatcher("firstname", match -> match.startsWith());

Example使用配置的合并視圖建立的查詢。預設比對設定可以在ExampleMatcher級别設定,而單獨的設定可以應用于特定的屬性路徑。已設定上的設定ExampleMatcher由屬性路徑設定繼承,除非它們被明确定義。屬性更新檔上的設定比預設設定具有更高的優先級。下表描述了各種ExampleMatcher設定的範圍:

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

運作示例

在 Spring Data JPA 中,您可以将 Query by Example 與 Repositories 一起使用,如下例所示:

示例 106. 使用存儲庫按示例查詢

public interface PersonRepository extends JpaRepository<Person, String> { … }

public class PersonService {

@Autowired PersonRepository personRepository;

public List<Person> findPeople(Person probe) {

return personRepository.findAll(Example.of(probe));

目前,隻有SingularAttribute屬性可以用于屬性比對。

屬性說明符接受屬性名稱(例如firstname和lastname)。您可以通過将屬性與點 ( address.city)連結在一起進行導航。您還可以使用比對選項和區分大小寫來調整它。

下表顯示了StringMatcher您可以使用的各種選項以及在名為 的字段上使用它們的結果firstname:

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

5.1.7. 交易性

預設情況下,從存儲庫執行個體繼承的 CRUD 方法SimpleJpaRepository是事務性的。對于讀取操作,事務配置readOnly标志設定為true。所有其他人都使用普通配置,@Transactional以便應用預設事務配置。由事務存儲庫片段支援的存儲庫方法從實際片段方法繼承事務屬性。

如果您需要為存儲庫中聲明的方法之一調整事務配置,請在存儲庫接口中重新聲明該方法,如下所示:

示例 107. CRUD 的自定義事務配置

public interface UserRepository extends CrudRepository<User, Long> {

@Override

@Transactional(timeout = 10)

public List<User> findAll();

// Further query method declarations

這樣做會導緻findAll()方法以 10 秒的逾時時間運作并且沒有readOnly标志。

改變事務行為的另一種方法是使用(通常)覆寫多個存儲庫的外觀或服務實作。其目的是為非 CRUD 操作定義事務邊界。以下示例展示了如何将這樣的外觀用于多個存儲庫:

示例 108. 使用 Facade 為多個存儲庫調用定義事務

@Service

public class UserManagementImpl implements UserManagement {

private final UserRepository userRepository;

private final RoleRepository roleRepository;

public UserManagementImpl(UserRepository userRepository,

RoleRepository roleRepository) {

this.userRepository = userRepository;

this.roleRepository = roleRepository;

@Transactional

public void addRoleToAllUsers(String roleName) {

Role role = roleRepository.findByName(roleName);

for (User user : userRepository.findAll()) {

user.addRole(role);

userRepository.save(user);

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

此示例導緻調用addRoleToAllUsers(…)在事務内運作(參與現有事務或建立新事務,如果尚未運作)。然後忽略存儲庫中的事務配置,因為外部事務配置決定了實際使用的事務配置。請注意,您必須顯式激活<tx:annotation-driven />或使用@

EnableTransactionManagement才能使外觀的基于注釋的配置工作。此示例假定您使用元件掃描。

請注意,save從 JPA 的角度來看,調用 to并不是絕對必要的,但仍應存在以與 Spring Data 提供的存儲庫抽象保持一緻。

事務查詢方法

要讓您的查詢方法具有事務性,請@Transactional在您定義的存儲庫接口處使用,如以下示例所示:

示例 109.在查詢方法中使用 @Transactional

@Transactional(readOnly = true)

interface UserRepository extends JpaRepository<User, Long> {

List<User> findByLastname(String lastname);

@Modifying

@Query("delete from User u where u.active = false")

void deleteInactiveUsers();

通常,您希望将該readOnly标志設定為true,因為大多數查詢方法隻讀取資料。與此相反,deleteInactiveUsers()使用@Modifying注釋并覆寫事務配置。是以,該方法在readOnly标志設定為 的情況下運作false。

您可以将事務用于隻讀查詢,并通過設定readOnly标志來标記它們。但是,這樣做并不能檢查您是否不會觸發操縱查詢(盡管某些資料庫拒絕INSERT和UPDATE隻讀事務中的語句)。該readOnly标志會作為對底層 JDBC 驅動程式的提示進行傳播,以進行性能優化。此外,Spring 對底層 JPA 提供程式執行了一些優化。例如,當與 Hibernate 一起使用時,重新整理模式NEVER在您将事務配置為時設定為readOnly,這會導緻 Hibernate 跳過髒檢查(對大對象樹的顯着改進)。

内容來源:Spring中國教育管理中心(Spring認證)

Spring認證中國教育管理中心-Spring Data JPA 參考文檔六

2021年2月,VMware公司正式與北京中科卓望網絡科技有限公司(以下簡稱:中科卓望)達成戰略合作,授予其 Spring 中國教育管理中心,攜手 VMware 全球最新 Spring技術和認證體系,幫助中國院校建構專業教學内容,全面賦能未來開發人。