Breaking

14 tháng 7, 2021

Spring Data JPA

 


Spring Data JPA

1.      Giới thiệu:

Spring Data JPA cung cấp hỗ trợ kho lưu trữ cho Java Persistence API (JPA). Nó giúp giảm bớt sự phát triển của các ứng dụng cần truy cập JPA data source.

1.1  Dữ liệu dự án:

·         Kiểm soát phiên bản: https://github.com/spring-projects/spring-data-jpa

·         Trình sửa lỗi: https://github.com/spring-projects/spring-data-jpa/issues

·         Kho lưu trữ phát hành: https://repo.spring.io/libs-release

·         Kho Milestone:  https://repo.spring.io/libs-milestone

·         Kho chụp ảnh nhanh:  https://repo.spring.io/libs-snapshot

 

2.                  Các phần mới và đáng chú ý của các phiên bản

 

2.1  Phiên bản JPA 1.11:

Spring Data JPA 1.11 đã thêm các tính năng sau:

·         Cải thiện tương thích với Hibernate 5.2.

·         Hỗ trợ so sánh chế độ hỗ trợ cho truy vấn theo ví dụ.

·         Tối ưu hóa truy vấn theo trang.

·         Hỗ trợ cho tồn tại sao chép chiếu trong kho lưu trữ truy xuất đầu ra.

 

2.2  Phiên bản 1.10:

Spring Data JPA 1.10 đã thêm các tính năng sau:

·         Hỗ trợ các phép chiếu trong các kho lưu trữ phương pháp.

·         Hỗ trợ cho Truy vấn theo ví dụ.

·         Các chú thích sau đây đã được kích hoạt để xây dựng trên bao gồm chú thích: @EntityGraph, @Lock, @Modify, @Query, @QueryHints và @Procedure.

·         Từ khóa hỗ trợ trên tập biểu thức.

·         AttributeConverter triển khai ZoneIdJSR-310 và ThreeTenBP.

·         Nâng cấp lên Querydsl 4, Hibernate 5, OpenJPA 2.4 và EclipseLink 2.6.1.

 

3.       Sự phụ thuộc:

Do ngày ra đời của các mô-đun Dữ liệu Mùa xuân riêng lẻ khác nhau, hầu hết chúng đều mang số phiên bản chính và phụ khác nhau. Cách dễ nhất để tìm những cái tương thích là dựa vào BOM Tàu phát hành dữ liệu mùa xuân mà chúng tôi gửi với các phiên bản tương thích được xác định. Trong một dự án Maven, bạn sẽ khai báo sự phụ thuộc này trong <dependencyManagement />phần POM của bạn như sau:

       Ví dụ 1: sử dụng spring data trong BOM:

 



 

Phiên bản  phát hành hiện tại là 2021.0.2. Phiên bản xe lửa sử dụng calver với mẫu YYYY.MINOR.MICRO. Tên phiên bản theo sau ${calver}cho các bản phát hành GA và bản phát hành dịch vụ và mẫu sau cho tất cả các phiên bản khác:, ${calver}-${modifier}trong đó modifiercó thể là một trong các tên sau:

·         SNAPSHOT: Ảnh chụp nhanh hiện tại

·         M1, M2v.v: Các cột mốc

·         RC1, RC2v.v .: Giải phóng các cử nhân ứng dụng

Bạn có thể tìm thấy một hoạt động ví dụ về việc sử dụng BOM trong kho lưu trữ ví dụ về Dữ liệu spring (https://github.com/spring-projects/spring-data-examples/tree/main/bom)  của chúng tôi. Với điều đó, bạn có thể khai báo các mô-đun dữ liệu mùa xuân mà bạn muốn sử dụng mà không có phiên bản trong khối <dependencies />, chẳng hạn như sau:

Ví dụ 2. Khai báo một phần phụ thuộc vào một mô-đun dữ liệu spring:




3.1  Quản lý phụ thuộc với Spring Boot

    Spring Boot chọn một phiên bản gần đây của mô-đun Dữ liệu Mùa xuân cho bạn. Nếu bạn vẫn muốn nâng cấp lên phiên bản mới hơn, hãy đặt thuộc spring-data-releasetrain.versiontính thành phiên bản tàu và phép lặp mà bạn muốn sử dụng.

3.2  Spring Framework

Phiên bản hiện tại của mô-đun Dữ liệu Mùa xuân yêu cầu Spring Framework 5.3.8 trở lên. Các mô-đun cũng có thể hoạt động với phiên bản sửa lỗi cũ hơn của phiên bản nhỏ đó. Tuy nhiên, bạn nên sử dụng phiên bản mới nhất trong thế hệ đó.

 

4.  Làm việc với kho dữ liệu Spring

Mục tiêu của việc trừu tượng hóa kho lưu trữ Dữ liệu Spring là giảm đáng kể số lượng mã soạn sẵn cần thiết để triển khai các lớp truy cập dữ liệu cho các kho lưu trữ liên tục khác nhau.

Tài liệu về kho dữ liệu Spring và kho dữ liệu của bạn

Chương này giải thích các khái niệm và giao diện cốt lõi của kho dữ liệu Spring. Thông tin trong chương này được lấy từ mô-đun Spring Data Commons. Nó sử dụng cấu hình và mẫu mã cho mô-đun Java Persistence API (JPA). Bạn nên điều chỉnh khai báo không gian tên XML và các kiểu được mở rộng cho tương đương của mô-đun cụ thể mà bạn sử dụng. “Tham chiếu không gian tên” bao gồm cấu hình XML, được hỗ trợ trên tất cả các mô-đun Dữ liệu mùa xuân hỗ trợ API kho lưu trữ. “Từ khóa truy vấn kho lưu trữ” bao gồm các từ khóa của phương pháp truy vấn được hỗ trợ bởi tính trừu tượng của kho lưu trữ nói chung. Để biết thông tin chi tiết về các tính năng cụ thể của mô-đun của bạn, hãy xem chương về mô-đun đó của tài liệu này.

 

4.1 Tài liệu cốt lõi

Giao diện trung tâm trong kho lưu trữ Dữ liệu Spring trừu tượng là Kho lưu trữ. Nó sử dụng lớp miền để quản lý cũng như kiểu ID của lớp miền làm đối số kiểu. Giao diện này chủ yếu hoạt động như một giao diện đánh dấu để nắm bắt các loại để làm việc và giúp bạn khám phá các giao diện mở rộng giao diện này. Giao diện CrudRepository cung cấp chức năng CRUD tinh vi cho lớp thực thể đang được quản lý.

 

Example 3. CrudRepository Interface

public interface CrudRepository<T, ID> extends Repository<T, ID> {

 

  <S extends T> S save(S entity);     // lưu thực thể đã cho

 

  Optional<T> findById(ID primaryKey); // trả về thực thể được xác định bởi ID

 

  Iterable<T> findAll();   // trả về tất cả thực thể           

 

  long count();       // Trả về số lượng thực thể                

 

  void delete(T entity);   // Xóa thực thể đã cho           

 

  boolean existsById(ID primaryKey);  // cho biết thực thể có ID đã cho có tồn tại hay không

 

  // … more functionality omitted.

}

Trên đầu trang của CrudRepository, có một bản tóm tắt PagingAndSortingRepository bổ sung các phương thức bổ sung để dễ dàng truy cập phân trang vào các thực thể:

Ví dụ 4. Giao diện PagingAndSortingRepository

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {

 

  Iterable<T> findAll(Sort sort);

 

  Page<T> findAll(Pageable pageable);

}

Để truy cập trang thứ hai của Người dùng với kích thước trang là 20, bạn có thể làm như sau:

PagingAndSortingRepository<User, Long> repository = // … get access to a bean

Page<User> users = repository.findAll(PageRequest.of(1, 20));

Ngoài các phương pháp truy vấn, có sẵn truy xuất dẫn xuất truy vấn cho cả truy vấn đếm và xóa. Danh sách sau đây hiển thị định nghĩa giao diện cho truy vấn số lượng dẫn xuất:

Ví dụ 5. Truy vấn số lượng có nguồn gốc

 

interface UserRepository extends CrudRepository<User, Long> {

 

  long countByLastname(String lastname);

}

Danh sách sau đây hiển thị định nghĩa giao diện cho truy vấn xóa dẫn xuất:

Ví dụ 6. Truy vấn xóa có nguồn gốc

 

interface UserRepository extends CrudRepository<User, Long> {

 

  long deleteByLastname(String lastname);

 

  List<User> removeByLastname(String lastname);

}

4.2. Phương thức truy vấn

Các kho chức năng CRUD tiêu chuẩn thường có các truy vấn trên kho dữ liệu bên dưới. Với Dữ liệu mùa xuân, việc khai báo các truy vấn đó sẽ trở thành một quy trình gồm bốn bước:

1.       Khai báo một giao diện mở rộng Kho lưu trữ hoặc một trong các giao diện con của nó và nhập nó vào lớp miền và loại ID mà nó sẽ xử lý, như được hiển thị trong ví dụ sau:

 

interface PersonRepository extends Repository<Person, Long> { … }

2.       Khai báo các phương thức truy vấn trên giao diện.

interface PersonRepository extends Repository<Person, Long> {

            List<Person> findByLastname(String lastname);

}

 

3.       Thiết lập Spring để tạo các phiên bản proxy cho các giao diện đó, bằng JavaConfig hoặc với cấu hình XML.

a.       Để sử dụng cấu hình Java, hãy tạo một lớp tương tự như sau:

import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

 

@EnableJpaRepositories

class Config { … }

 

b.       Để sử dụng cấu hình XML, hãy xác định một bean tương tự như sau:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:jpa="http://www.springframework.org/schema/data/jpa"

   xsi:schemaLocation="http://www.springframework.org/schema/beans

     https://www.springframework.org/schema/beans/spring-beans.xsd

     http://www.springframework.org/schema/data/jpa

     https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

 

   <jpa:repositories base-package="com.acme.repositories"/>

 

</beans>

            Không gian tên JPA được sử dụng trong ví dụ này. Nếu bạn sử dụng trừu tượng kho lưu trữ cho bất kỳ cửa hàng nào khác, bạn cần thay đổi điều này thành khai báo không gian tên thích hợp của mô-đun cửa hàng của bạn. Nói cách khác, bạn nên trao đổi jpa có lợi, ví dụ như mongodb.

Ngoài ra, lưu ý rằng biến thể JavaConfig không định cấu hình gói một cách rõ ràng, vì gói của lớp chú thích được sử dụng theo mặc định. Để tùy chỉnh gói để quét, hãy sử dụng một trong các thuộc tính basePackage… của kho lưu trữ dữ liệu cụ thể của @ Enable $ {store} Repositories-annotation.

4.       Chèn cá thể kho lưu trữ và sử dụng nó, như được hiển thị trong ví dụ sau:

class SomeClient {

 

  private final PersonRepository repository;

 

  SomeClient(PersonRepository repository) {

    this.repository = repository;

  }

 

  void doSomething() {

    List<Person> persons = repository.findByLastname("Matthews");

  }

}

Các phần tiếp theo giải thích chi tiết từng bước:

-          Xác định giao diện kho lưu trữ

-          Định nghĩa các phương thức truy vấn

-          Tạo phiên bản kho lưu trữ

-          Triển khai tùy chỉnh cho Kho lưu trữ dữ liệu mùa xuân

4.3. Xác định giao diện kho lưu trữ

Để xác định giao diện kho lưu trữ, trước tiên bạn cần xác định giao diện kho lưu trữ dành riêng cho lớp miền. Giao diện phải mở rộng Kho lưu trữ và được nhập vào lớp miền và loại ID. Nếu bạn muốn hiển thị các phương thức CRUD cho loại miền đó, hãy mở rộng CrudRepository thay vì Repository.

4.3.1. Tinh chỉnh Định nghĩa Kho lưu trữ

Thông thường, giao diện kho lưu trữ của bạn mở rộng Kho lưu trữ, CrudRepository hoặc PagingAndSortingRepository. Ngoài ra, nếu bạn không muốn mở rộng giao diện Spring Data, bạn cũng có thể chú thích giao diện kho lưu trữ của mình bằng @RepositoryDefinition. Việc mở rộng CrudRepository cho thấy một bộ hoàn chỉnh các phương pháp để thao túng các thực thể của bạn. Nếu bạn muốn chọn lọc các phương pháp được hiển thị, hãy sao chép các phương thức bạn muốn hiển thị từ CrudRepository vào kho lưu trữ miền của bạn.

Làm như vậy cho phép bạn xác định các phần tóm tắt của riêng mình trên chức năng Kho lưu trữ dữ liệu mùa xuân được cung cấp.

Ví dụ sau đây cho thấy cách hiển thị có chọn lọc các phương thức CRUD (findById và save, trong trường hợp này):

Ví dụ 7. Hiển thị có chọn lọc các phương pháp CRUD

@NoRepositoryBean

interface MyBaseRepository<T, ID> extends Repository<T, ID> {

 

  Optional<T> findById(ID id);

 

  <S extends T> S save(S entity);

}

 

interface UserRepository extends MyBaseRepository<User, Long> {

  User findByEmailAddress(EmailAddress emailAddress);

}

Trong ví dụ trước, bạn đã xác định một giao diện cơ sở chung cho tất cả các kho lưu trữ miền của mình và hiển thị findById (…) cũng như save (…). ví dụ: nếu bạn sử dụng JPA, việc triển khai là SimpleJpaRepository), vì chúng khớp với chữ ký phương thức trong CrudRepository. Vì vậy, UserRepository hiện có thể lưu người dùng, tìm từng người dùng theo ID và kích hoạt truy vấn để tìm Người dùng theo địa chỉ email.

Giao diện kho lưu trữ trung gian được chú thích bằng @NoRepositoryBean. Đảm bảo rằng bạn thêm chú thích đó vào tất cả các giao diện kho lưu trữ mà Dữ liệu Spring sẽ không tạo phiên bản trong thời gian chạy.

4.3.2. Sử dụng kho lưu trữ với nhiều mô-đun dữ liệu mùa xuân

Sử dụng một mô-đun Dữ liệu Spring duy nhất trong ứng dụng của bạn làm cho mọi thứ trở nên đơn giản, bởi vì tất cả các giao diện kho lưu trữ trong phạm vi đã xác định đều bị ràng buộc với mô-đun Dữ liệu Spring. Đôi khi, các ứng dụng yêu cầu sử dụng nhiều hơn một mô-đun Dữ liệu Spring. Trong những trường hợp như vậy, định nghĩa kho lưu trữ phải phân biệt giữa các công nghệ bền bỉ. Khi nó phát hiện nhiều nhà máy kho lưu trữ trên đường dẫn lớp, Spring Data sẽ đi vào chế độ cấu hình kho lưu trữ nghiêm ngặt. Cấu hình nghiêm ngặt sử dụng chi tiết về kho lưu trữ hoặc lớp miền để quyết định về liên kết mô-đun Dữ liệu Spring cho định nghĩa kho lưu trữ:

1.       Nếu định nghĩa kho lưu trữ mở rộng kho lưu trữ dành riêng cho mô-đun, thì nó là một ứng cử viên hợp lệ cho mô-đun Dữ liệu mùa xuân cụ thể.

2.       Nếu lớp miền được chú thích bằng chú thích loại mô-đun cụ thể, thì nó là một ứng cử viên hợp lệ cho mô-đun Dữ liệu mùa xuân cụ thể. Mô-đun Spring Data chấp nhận các chú thích của bên thứ ba (chẳng hạn như JPA’s @Entity) hoặc cung cấp các chú thích của riêng họ (chẳng hạn như @Document cho Spring Data MongoDB và Spring Data Elasticsearch).

Ví dụ sau cho thấy một kho lưu trữ sử dụng các giao diện dành riêng cho mô-đun (JPA trong trường hợp này):

Ví dụ 8. Định nghĩa kho lưu trữ sử dụng giao diện dành riêng cho mô-đun

interface MyRepository extends JpaRepository<User, Long> { }

 

@NoRepositoryBean

interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }

 

interface UserRepository extends MyBaseRepository<User, Long> { … }

MyRepository và UserRepository mở rộng JpaRepository trong hệ thống phân cấp loại của chúng. Họ là những ứng cử viên hợp lệ cho mô-đun Spring Data JPA.

Ví dụ sau đây cho thấy một kho lưu trữ sử dụng các giao diện chung:

Ví dụ 9. Định nghĩa kho lưu trữ sử dụng giao diện chung

interface AmbiguousRepository extends Repository<User, Long> { … }

 

@NoRepositoryBean

interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }

 

interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { … }

 

AmbiguousRepository và AmbiguousUserRepository chỉ mở rộng Repository và CrudRepository trong hệ thống phân cấp loại của chúng. Mặc dù điều này là tốt khi sử dụng một mô-đun Dữ liệu mùa xuân duy nhất, nhưng nhiều mô-đun không thể phân biệt Dữ liệu mùa xuân cụ thể nào mà các kho lưu trữ này nên bị ràng buộc.

Ví dụ sau cho thấy một kho lưu trữ sử dụng các lớp miền với các chú thích:

Ví dụ 10. Định nghĩa kho lưu trữ sử dụng các lớp miền có chú thích

interface PersonRepository extends Repository<Person, Long> { … }

 

@Entity

class Person { … }

 

interface UserRepository extends Repository<User, Long> { … }

 

@Document

class User { … }

 

Ví dụ 11. Định nghĩa kho lưu trữ sử dụng các lớp miền với các chú thích hỗn hợp

interface JpaPersonRepository extends Repository<Person, Long> { … }

 

interface MongoDBPersonRepository extends Repository<Person, Long> { … }

 

@Entity

@Document

class Person { … }

Chi tiết loại kho lưu trữ và chú thích phân biệt lớp miền được sử dụng cho cấu hình kho lưu trữ nghiêm ngặt để xác định các ứng cử viên kho lưu trữ cho một mô-đun Dữ liệu mùa xuân cụ thể. Có thể sử dụng nhiều chú thích dành riêng cho công nghệ bền vững trên cùng một loại miền và cho phép sử dụng lại các loại miền trên nhiều công nghệ bền vững. Tuy nhiên, Spring Data sau đó không còn có thể xác định một mô-đun duy nhất để liên kết kho lưu trữ.

 

Cách cuối cùng để phân biệt các kho lưu trữ là xác định phạm vi các gói cơ sở của kho lưu trữ. Các gói cơ sở xác định các điểm bắt đầu để quét các định nghĩa giao diện kho lưu trữ, nghĩa là có các định nghĩa kho lưu trữ nằm trong các gói thích hợp. Theo mặc định, cấu hình theo hướng chú thích sử dụng gói của lớp cấu hình. Gói cơ sở trong cấu hình dựa trên XML là bắt buộc.

Ví dụ 12. Cấu hình theo hướng chú thích của gói cơ sở

@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa")

@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo")

class Configuration { … }

4.4. Định nghĩa các phương thức truy vấn

Proxy kho lưu trữ có hai cách để lấy một truy vấn cửa hàng cụ thể từ tên phương thức:

-          Bằng cách lấy truy vấn trực tiếp từ tên phương thức.

-          Bằng cách sử dụng một truy vấn được xác định theo cách thủ công.

Bằng cách sử dụng một truy vấn được xác định theo cách thủ công.

4.4.1. Các chiến lược tra cứu truy vấn

Các chiến lược sau đây có sẵn cho cơ sở hạ tầng kho lưu trữ để giải quyết truy vấn. Với cấu hình XML, bạn có thể định cấu hình chiến lược tại không gian tên thông qua thuộc tính chiến lược truy vấn-tra cứu. Đối với cấu hình Java, bạn có thể sử dụng thuộc tính queryLookupStrategy của chú thích Bật kho lưu trữ $ {store}. Một số chiến lược có thể không được hỗ trợ cho các kho dữ liệu cụ thể.

-          CREATE cố gắng tạo một truy vấn dành riêng cho cửa hàng từ tên phương thức truy vấn. Cách tiếp cận chung là loại bỏ một tập hợp các tiền tố nổi tiếng nhất định khỏi tên phương thức và phân tích cú pháp phần còn lại của phương thức. Bạn có thể đọc thêm về xây dựng truy vấn trong “Tạo Truy vấn”.

-          USE_DECLARED_QUERY cố gắng tìm một truy vấn đã khai báo và ném một ngoại lệ nếu nó không thể tìm thấy một ngoại lệ. Truy vấn có thể được xác định bằng chú thích ở đâu đó hoặc được khai báo bằng các phương tiện khác. Xem tài liệu của cửa hàng cụ thể để tìm các tùy chọn có sẵn cho cửa hàng đó. Nếu cơ sở hạ tầng kho lưu trữ không tìm thấy truy vấn đã khai báo cho phương thức tại thời điểm khởi động, thì nó không thành công.

-          CREATE_IF_NOT_FOUND (mặc định) kết hợp CREATE và USE_DECLARED_QUERY. Nó tìm kiếm một truy vấn đã khai báo trước và nếu không tìm thấy truy vấn đã khai báo nào, nó sẽ tạo một truy vấn dựa trên tên phương thức tùy chỉnh. Đây là chiến lược tra cứu mặc định và do đó, được sử dụng nếu bạn không định cấu hình bất cứ thứ gì một cách rõ ràng. Nó cho phép định nghĩa truy vấn nhanh theo tên phương thức nhưng cũng có thể điều chỉnh tùy chỉnh các truy vấn này bằng cách giới thiệu các truy vấn đã khai báo khi cần thiết.

4.4.2. Query Creation

Cơ chế trình tạo truy vấn được tích hợp trong cơ sở hạ tầng kho lưu trữ Dữ liệu Mùa xuân rất hữu ích để xây dựng các truy vấn ràng buộc trên các thực thể của kho lưu trữ.

Ví dụ sau đây cho thấy cách tạo một số truy vấn:

Ví dụ 13. Tạo truy vấn từ tên phương thức

interface PersonRepository extends Repository<Person, Long> {

 

  List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);

 

  // Enables the distinct flag for the query

  List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);

  List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);

 

  // Enabling ignoring case for an individual property

  List<Person> findByLastnameIgnoreCase(String lastname);

  // Enabling ignoring case for all suitable properties

  List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);

 

  // Enabling static ORDER BY for a query

  List<Person> findByLastnameOrderByFirstnameAsc(String lastname);

  List<Person> findByLastnameOrderByFirstnameDesc(String lastname);

}

Phân tích cú pháp tên phương thức truy vấn được chia thành chủ đề và vị ngữ. Phần đầu tiên (tìm… Bởi, tồn tại… Bằng) xác định chủ đề của truy vấn, phần thứ hai tạo thành vị ngữ. Mệnh đề giới thiệu (chủ đề) có thể chứa các biểu thức khác. Bất kỳ văn bản nào giữa find (hoặc các từ khóa giới thiệu khác) và By đều được coi là mang tính mô tả trừ khi sử dụng một trong các từ khóa giới hạn kết quả, chẳng hạn như Distinction để đặt cờ khác biệt trên truy vấn sẽ được tạo hoặc Top / First để giới hạn kết quả truy vấn.

Phụ lục chứa danh sách đầy đủ các từ khóa chủ đề của phương pháp truy vấn và các từ khóa vị ngữ của phương thức truy vấn bao gồm các công cụ sắp xếp và sửa đổi cách viết hoa. Tuy nhiên, By đầu tiên hoạt động như một dấu phân cách để chỉ ra phần bắt đầu của vị từ tiêu chí thực tế. Ở cấp độ rất cơ bản, bạn có thể xác định các điều kiện trên thuộc tính thực thể và nối chúng với And và Or.

Kết quả thực sự của việc phân tích cú pháp phương thức phụ thuộc vào kho lưu trữ lâu dài mà bạn tạo truy vấn. Tuy nhiên, có một số điều chung cần lưu ý:

-          Các biểu thức thường là các đường truyền thuộc tính được kết hợp với các toán tử có thể được nối với nhau. Bạn có thể kết hợp các biểu thức thuộc tính với AND và OR. Bạn cũng nhận được hỗ trợ cho các toán tử như Between, LessThan, GreaterThan và Like cho các biểu thức thuộc tính. Các toán tử được hỗ trợ có thể khác nhau tùy theo kho dữ liệu, vì vậy hãy tham khảo phần thích hợp trong tài liệu tham khảo của bạn.

-          Bộ phân tích cú pháp phương thức hỗ trợ thiết lập cờ Bỏ qua cho các thuộc tính riêng lẻ (ví dụ: findByLastnameIgnoreCase (…)) hoặc cho tất cả các thuộc tính của kiểu hỗ trợ bỏ qua chữ hoa chữ thường (thường là các trường hợp Chuỗi - ví dụ: findByLastnameAndFirstnameAllIgnoreCase (…)). Việc bỏ qua các trường hợp được hỗ trợ có thể khác nhau tùy theo cửa hàng hay không, vì vậy hãy tham khảo các phần có liên quan trong tài liệu tham khảo để biết phương pháp truy vấn dành riêng cho cửa hàng.

-          Bạn có thể áp dụng thứ tự tĩnh bằng cách thêm mệnh đề OrderBy vào phương thức truy vấn tham chiếu đến thuộc tính và bằng cách cung cấp hướng sắp xếp (Asc hoặc Desc). Để tạo phương thức truy vấn hỗ trợ sắp xếp động, hãy xem "Xử lý tham số đặc biệt".

-           

4.4.3. Biểu thức tài sản

Biểu thức thuộc tính chỉ có thể tham chiếu đến thuộc tính trực tiếp của thực thể được quản lý, như được hiển thị trong ví dụ trước. Tại thời điểm tạo truy vấn, bạn đã đảm bảo rằng thuộc tính được phân tích cú pháp là thuộc tính của lớp miền được quản lý. Tuy nhiên, bạn cũng có thể xác định các ràng buộc bằng cách duyệt qua các thuộc tính lồng nhau. Hãy xem xét chữ ký phương thức sau:

List<Person> findByAddressZipCode(ZipCode zipCode);

Giả sử một người có địa chỉ với mã ZipCode. Trong trường hợp đó, phương thức tạo truyền tải thuộc tính x.address.zipCode. Thuật toán phân giải bắt đầu bằng cách diễn giải toàn bộ phần (AddressZipCode) là thuộc tính và kiểm tra lớp miền để tìm thuộc tính có tên đó (không viết hoa). Nếu thuật toán thành công, nó sẽ sử dụng thuộc tính đó. Nếu không, thuật toán sẽ tách nguồn tại các phần vỏ lạc đà từ phía bên phải thành đầu và đuôi và cố gắng tìm thuộc tính tương ứng - trong ví dụ của chúng tôi là AddressZip và Code. Nếu thuật toán tìm thấy một thuộc tính có phần đầu đó, nó sẽ lấy phần đuôi và tiếp tục xây dựng cây từ đó, tách phần đuôi lên theo cách vừa mô tả. Nếu lần phân tách đầu tiên không khớp, thuật toán sẽ di chuyển điểm phân tách sang trái (Địa chỉ, Mã ZipCode) và tiếp tục.

Mặc dù điều này sẽ hoạt động đối với hầu hết các trường hợp, nhưng thuật toán có thể chọn sai thuộc tính. Giả sử lớp Person cũng có thuộc tính addressZip. Thuật toán sẽ khớp trong vòng phân tách đầu tiên, chọn thuộc tính sai và thất bại (vì loại addressZip có thể không có thuộc tính mã).

 

Để giải quyết sự không rõ ràng này, bạn có thể sử dụng _ bên trong tên phương thức của mình để xác định thủ công các điểm truyền tải. Vì vậy, tên phương thức của chúng tôi sẽ như sau:

List<Person> findByAddress_ZipCode(ZipCode zipCode);

Bởi vì chúng tôi coi ký tự gạch dưới là ký tự dành riêng, chúng tôi đặc biệt khuyên bạn nên tuân theo các quy ước đặt tên tiêu chuẩn của Java (nghĩa là không sử dụng dấu gạch dưới trong tên thuộc tính mà thay vào đó sử dụng chữ hoa camel).

 

4.4.4. Xử lý thông số đặc biệt

Để xử lý các tham số trong truy vấn của bạn, hãy xác định các tham số phương thức như đã thấy trong các ví dụ trước. Bên cạnh đó, cơ sở hạ tầng nhận dạng một số loại cụ thể như Có thể gắn thẻ và Sắp xếp, để áp dụng phân trang và sắp xếp cho các truy vấn của bạn một cách linh hoạt. Ví dụ sau minh họa các tính năng này:

Ví dụ 14. Sử dụng Pagable, Slice và Sort trong các phương thức truy vấn

Page<User> findByLastname(String lastname, Pageable pageable);

 

Slice<User> findByLastname(String lastname, Pageable pageable);

 

List<User> findByLastname(String lastname, Sort sort);

 

List<User> findByLastname(String lastname, Pageable pageable);

Các API sử dụng Sắp xếp và Có thể gắn thẻ mong đợi các giá trị không rỗng sẽ được chuyển vào các phương thức. Nếu bạn không muốn áp dụng bất kỳ sắp xếp hoặc phân trang nào, hãy sử dụng Sort.unsorted () và Pagnable.unpaged ().

Phương thức đầu tiên cho phép bạn chuyển một phiên bản org.springframework.data.domain.Pagable vào phương thức truy vấn để thêm động phân trang vào truy vấn được xác định tĩnh của bạn. Một Trang biết về tổng số phần tử và số trang có sẵn. Nó làm như vậy bởi cơ sở hạ tầng kích hoạt một truy vấn đếm để tính toán con số tổng thể. Vì điều này có thể đắt (tùy thuộc vào cửa hàng được sử dụng), thay vào đó bạn có thể trả lại một Lát. Một Slice chỉ biết về việc có sẵn một Slice tiếp theo hay không, điều này có thể đủ khi xem qua một tập kết quả lớn hơn.

Các tùy chọn sắp xếp cũng được xử lý thông qua phiên bản Pagable. Nếu bạn chỉ cần sắp xếp, hãy thêm tham số org.springframework.data.domain.Sort vào phương thức của bạn. Như bạn có thể thấy, việc trả lại một Danh sách cũng có thể thực hiện được. Trong trường hợp này, siêu dữ liệu bổ sung cần thiết để xây dựng phiên bản Trang thực tế sẽ không được tạo (do đó, có nghĩa là truy vấn số lượng bổ sung đáng lẽ cần thiết sẽ không được đưa ra). Thay vào đó, nó hạn chế truy vấn chỉ tra cứu phạm vi thực thể nhất định.

 

Để biết bạn nhận được bao nhiêu trang cho toàn bộ truy vấn, bạn phải kích hoạt một truy vấn đếm bổ sung. Theo mặc định, truy vấn này có nguồn gốc từ truy vấn mà bạn thực sự kích hoạt.

 

Phân trang và sắp xếp

Bạn có thể xác định các biểu thức sắp xếp đơn giản bằng cách sử dụng tên thuộc tính. Bạn có thể nối các biểu thức để thu thập nhiều tiêu chí vào một biểu thức.

Ví dụ 15. Định nghĩa biểu thức sắp xếp

Sort sort = Sort.by("firstname").ascending()

  .and(Sort.by("lastname").descending());

Để có một cách an toàn hơn về kiểu để xác định biểu thức sắp xếp, hãy bắt đầu với kiểu để xác định biểu thức sắp xếp và sử dụng tham chiếu phương thức để xác định các thuộc tính cần sắp xếp.

Ví dụ 16. Định nghĩa các biểu thức sắp xếp bằng cách sử dụng API kiểu an toàn

TypedSort<Person> person = Sort.sort(Person.class);

 

Sort sort = person.by(Person::getFirstname).ascending()

  .and(person.by(Person::getLastname).descending());

TypedSort.by (…) sử dụng proxy thời gian chạy bằng cách (thường) sử dụng CGlib, điều này có thể cản trở quá trình biên dịch hình ảnh gốc khi sử dụng các công cụ như Graal VM Native.

Nếu triển khai cửa hàng của bạn hỗ trợ Querydsl, bạn cũng có thể sử dụng các loại siêu mô hình đã tạo để xác định biểu thức sắp xếp:

Ví dụ 17. Định nghĩa các biểu thức sắp xếp bằng cách sử dụng API Querydsl

QSort sort = QSort.by(QPerson.firstname.asc())

  .and(QSort.by(QPerson.lastname.desc()));

4.4.5. Giới hạn kết quả truy vấn

Bạn có thể giới hạn kết quả của các phương pháp truy vấn bằng cách sử dụng từ khóa đầu tiên hoặc từ khóa hàng đầu mà bạn có thể sử dụng thay thế cho nhau. Bạn có thể nối một giá trị số tùy chọn lên trên cùng hoặc đầu tiên để chỉ định kích thước kết quả tối đa được trả về. Nếu số bị bỏ trống, kích thước kết quả là 1 được giả định. Ví dụ sau cho thấy cách giới hạn kích thước truy vấn:

Ví dụ 18. Giới hạn kích thước kết quả của một truy vấn với Trên cùng và Đầu tiên

User findFirstByOrderByLastnameAsc();

 

User findTopByOrderByAgeDesc();

 

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

 

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

 

List<User> findFirst10ByLastname(String lastname, Sort sort);

 

List<User> findTop10ByLastname(String lastname, Pageable pageable);

Các biểu thức giới hạn cũng hỗ trợ từ khóa Khác biệt cho các kho dữ liệu hỗ trợ các truy vấn riêng biệt. Ngoài ra, đối với các truy vấn giới hạn kết quả được đặt thành một trường hợp, việc bao bọc kết quả bằng từ khóa Tùy chọn được hỗ trợ.

Nếu phân trang hoặc phân trang được áp dụng cho phân trang truy vấn giới hạn (và tính toán số lượng trang có sẵn), thì nó sẽ được áp dụng trong kết quả giới hạn.

Giới hạn kết quả kết hợp với sắp xếp động bằng cách sử dụng tham số Sắp xếp cho phép bạn thể hiện các phương pháp truy vấn cho phần tử 'K' nhỏ nhất cũng như cho phần tử lớn nhất 'K'.

4.4.6. Phương thức kho lưu trữ Trả lại Bộ sưu tập hoặc Lặp lại

Các phương thức truy vấn trả về nhiều kết quả có thể sử dụng Java Iterable, List và Set tiêu chuẩn. Ngoài ra, chúng tôi hỗ trợ trả lại Spring Data’s Streamable, một phần mở rộng tùy chỉnh của Iterable, cũng như các loại bộ sưu tập do Vavr cung cấp. Tham khảo phụ lục giải thích tất cả các kiểu trả về phương thức truy vấn có thể có.

 

Sử dụng Streamable làm Loại trả lại của phương thức truy vấn

Bạn có thể sử dụng Streamable để thay thế cho Iterable hoặc bất kỳ loại tập hợp nào. Nó cung cấp các phương thức tiện lợi để truy cập một Luồng không song song (không có trong Iterable) và khả năng trực tiếp… .filter (…) và… .map (…) qua các phần tử và nối Streamable với những phần tử khác:

Ví dụ 19. Sử dụng Streamable để kết hợp các kết quả của phương pháp truy vấn

interface PersonRepository extends Repository<Person, Long> {

  Streamable<Person> findByFirstnameContaining(String firstname);

  Streamable<Person> findByLastnameContaining(String lastname);

}

 

Streamable<Person> result = repository.findByFirstnameContaining("av")

  .and(repository.findByLastnameContaining("ea"));

 

Trả lại các loại trình bao bọc có thể truyền trực tiếp tùy chỉnh

Cung cấp các loại trình bao bọc chuyên dụng cho các bộ sưu tập là một mẫu thường được sử dụng để cung cấp một API cho một kết quả truy vấn trả về nhiều phần tử. Thông thường, những kiểu này được sử dụng bằng cách gọi một phương thức kho lưu trữ trả về kiểu giống như tập hợp và tạo một thể hiện của kiểu trình bao bọc theo cách thủ công. Bạn có thể tránh bước bổ sung đó vì Dữ liệu mùa xuân cho phép bạn sử dụng các loại trình bao bọc này làm loại trả về phương thức truy vấn nếu chúng đáp ứng các tiêu chí sau:

1.       Loại thực hiện Streamable.

2.       Kiểu hiển thị phương thức khởi tạo hoặc phương thức nhà máy tĩnh có tên là (…) hoặc valueOf (…) lấy Streamable làm đối số.

 

Danh sách sau đây cho thấy một ví dụ:

class Product {                                        

  MonetaryAmount getPrice() { … } //(1)

}

 

@RequiredArgConstructor(staticName = "of")

class Products implements Streamable<Product> { // (2)

 

  private Streamable<Product> streamable;

 

  public MonetaryAmount getTotal() {                   

    return streamable.stream()

      .map(Priced::getPrice)

      .reduce(Money.of(0), MonetaryAmount::add); (3)

  }

 

 

  @Override

  public Iterator<Product> iterator() {                

    return streamable.iterator();  //(4)

  }

}

 

interface ProductRepository implements Repository<Product, Long> {

  Products findAllByDescriptionContaining(String text); (5)

}

(1) Một thực thể product để lộ API để truy cập vào giá của sản phẩm.

(2) Một loại trình bao bọc cho một Streamable<Product> có thể truyền trực tuyến có thể được xây dựng bằng cách sử dụng Products.of (…) (phương thức gốc được tạo bằng chú thích Lombok).

Một hàm tạo chuẩn sử dụng Streamable<Product> có thể truyền trực tuyến cũng sẽ làm được điều đó.       

(3) Loại trình bao bọc hiển thị một API bổ sung, tính toán các giá trị mới trên Streamable<Product> có thể truyền trực tuyến.

(4) Triển khai giao diện Streamable và ủy quyền cho kết quả thực tế.

(5) Loại trình bao bọc đó Sản phẩm có thể được sử dụng trực tiếp làm kiểu trả về của phương thức truy vấn.

Bạn không cần phải trả lại Streamable <Sản phẩm> và bọc nó theo cách thủ công sau khi truy vấn trong ứng dụng khách kho lưu trữ.

 

Hỗ trợ cho Bộ sưu tập Vavr

Vavr là một thư viện bao gồm các khái niệm lập trình hàm trong Java. Nó đi kèm với một tập hợp các loại tập hợp tùy chỉnh mà bạn có thể sử dụng làm các loại trả về của phương thức truy vấn, như bảng sau cho thấy:

Bạn có thể sử dụng các kiểu trong cột đầu tiên (hoặc các kiểu con của chúng) làm kiểu trả về của phương thức truy vấn và lấy các kiểu trong cột thứ hai được sử dụng làm kiểu triển khai, tùy thuộc vào kiểu Java của kết quả truy vấn thực tế (cột thứ ba). Ngoài ra, bạn có thể khai báo Traversable (tương đương với Vavr Iterable) và sau đó chúng tôi lấy lớp triển khai từ giá trị trả về thực tế. Nghĩa là, java.util.List được chuyển thành Vavr List hoặc Seq, java.util.Set trở thành Vavr LinkedHashSet Set, v.v.

 

4.4.7. Xử lý vô hiệu các phương thức kho lưu trữ

Kể từ Spring Data 2.0, các phương thức CRUD của kho lưu trữ trả về một phiên bản tổng hợp riêng lẻ sử dụng Java 8’s Optional để chỉ ra khả năng không có giá trị. Bên cạnh đó, Spring Data hỗ trợ trả về các loại trình bao bọc sau trên các phương thức truy vấn:

·         com.google.common.base.Optional

·         scala.Option

·         io.vavr.control.Option

Ngoài ra, các phương pháp truy vấn có thể chọn hoàn toàn không sử dụng loại trình bao bọc. Khi đó, việc không có kết quả truy vấn được chỉ ra bằng cách trả về null. Các phương thức kho lưu trữ trả về tập hợp, lựa chọn thay thế tập hợp, trình bao bọc và luồng được đảm bảo không bao giờ trả về giá trị rỗng mà thay vào đó là biểu diễn trống tương ứng. Xem “Các kiểu trả về truy vấn kho lưu trữ” để biết chi tiết.

 

Chú thích vô hiệu

Bạn có thể thể hiện các ràng buộc về tính vô hiệu cho các phương thức kho lưu trữ bằng cách sử dụng các chú thích về tính vô hiệu của Spring Framework. Họ cung cấp một cách tiếp cận thân thiện với công cụ và chọn tham gia kiểm tra rỗng trong thời gian chạy, như sau:

·         @NonNullApi: Được sử dụng ở cấp độ gói để khai báo rằng hành vi mặc định cho các tham số và giá trị trả về tương ứng là không chấp nhận cũng không tạo ra giá trị null.

·         @NonNull: Được sử dụng trên một tham số hoặc giá trị trả về không được rỗng (không cần thiết cho một tham số và giá trị trả về nếu áp dụng @NonNullApi).

·         @Nullable: Được sử dụng trên một tham số hoặc giá trị trả về có thể là giá trị rỗng.

Chú thích Spring được chú thích meta với chú thích JSR 305 (một JSR không hoạt động nhưng được sử dụng rộng rãi). Các siêu chú thích JSR 305 cho phép các nhà cung cấp công cụ (chẳng hạn như IDEA, Eclipse và Kotlin) cung cấp hỗ trợ null-an toàn theo cách chung chung mà không cần phải hỗ trợ mã cứng cho các chú thích Spring. Để bật tính năng kiểm tra thời gian chạy các ràng buộc về tính nullability cho các phương thức truy vấn, bạn cần kích hoạt tính không nullability ở cấp độ gói bằng cách sử dụng Spring’s @NonNullApi trong package-info.java, như được hiển thị trong ví dụ sau:

Ví dụ 20. Khai báo tính không nullability trong package-info.java

@org.springframework.lang.NonNullApi

package com.acme;

Sau khi cài đặt mặc định không null, các lệnh gọi phương thức truy vấn kho lưu trữ sẽ được xác thực trong thời gian chạy đối với các ràng buộc về tính null. Nếu một kết quả truy vấn vi phạm ràng buộc đã xác định, một ngoại lệ sẽ được ném ra. Điều này xảy ra khi phương thức sẽ trả về null nhưng được khai báo là không thể null (mặc định với chú thích được xác định trên gói chứa kho lưu trữ). Nếu bạn muốn chọn lại kết quả có thể vô hiệu, hãy sử dụng có chọn lọc @Nullable trên các phương pháp riêng lẻ. Việc sử dụng các loại trình bao bọc kết quả được đề cập ở đầu phần này tiếp tục hoạt động như mong đợi: một kết quả trống được dịch thành giá trị đại diện cho sự vắng mặt.

Ví dụ sau đây cho thấy một số kỹ thuật vừa được mô tả:

Ví dụ 21. Sử dụng các ràng buộc nullability khác nhau

package com.acme;       (1)                                               

 

import org.springframework.lang.Nullable;

 

interface UserRepository extends Repository<User, Long> {

 

  User getByEmailAddress(EmailAddress emailAddress); (2)                   

 

  @Nullable

  User findByEmailAddress(@Nullable EmailAddress emailAdress);  (3)       

 

  Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress); (4)

}

(1) Kho lưu trữ nằm trong một gói (hoặc gói con) mà chúng tôi đã xác định hành vi không rỗng.

(2) Ném một EmptyResultDataAccessException khi truy vấn không tạo ra kết quả. Ném một IllegalArgumentException khi emailAddress được chuyển đến phương thức là trống.

(3) Trả về null khi truy vấn không tạo ra kết quả. Cũng chấp nhận null làm giá trị cho emailAddress.

(4) Trả về Optional.empty () khi truy vấn không tạo ra kết quả. Ném một IllegalArgumentException khi emailAddress được chuyển đến phương thức là trống.

Tính vô hiệu trong Kho lưu trữ dựa trên Kotlin

Kotlin có định nghĩa về các ràng buộc vô hiệu được đưa vào ngôn ngữ. Mã Kotlin biên dịch thành bytecode, không thể hiện các ràng buộc về tính null thông qua các chữ ký phương thức mà là thông qua siêu dữ liệu được biên dịch trong. Đảm bảo bao gồm JAR phản ánh kotlin trong dự án của bạn để cho phép xem xét các ràng buộc về tính vô hiệu của Kotlin. Kho lưu trữ Dữ liệu mùa xuân sử dụng cơ chế ngôn ngữ để xác định các ràng buộc đó để áp dụng các kiểm tra thời gian chạy giống nhau, như sau:

Ví dụ 22. Sử dụng ràng buộc tính nullability trên kho lưu trữ Kotlin

interface UserRepository : Repository<User, String> {

 

  fun findByUsername(username: String): User     (1)

 

  fun findByFirstname(firstname: String?): User? (2)

}

(1) Phương thức xác định cả tham số và kết quả là không thể nullable (mặc định Kotlin). Trình biên dịch Kotlin từ chối các lệnh gọi phương thức chuyển null cho phương thức. Nếu truy vấn trả về một kết quả trống, thì một ngoại lệ EmptyResultDataAccessException sẽ được ném ra.

(2) Phương thức này chấp nhận null cho tham số firstname và trả về null nếu truy vấn không tạo ra kết quả.

4.4.8. Truyền trực tuyến kết quả truy vấn

Bạn có thể xử lý tăng dần kết quả của các phương thức truy vấn bằng cách sử dụng Java 8 Stream <T> làm kiểu trả về. Thay vì gói kết quả truy vấn trong Luồng, các phương pháp dành riêng cho kho dữ liệu được sử dụng để thực hiện luồng, như được minh họa trong ví dụ sau:

Ví dụ 23. Truyền kết quả của một truy vấn với Java 8 Stream <T>

@Query("select u from User u")

Stream<User> findAllByCustomQueryAndStream();

 

Stream<User> readAllByFirstnameNotNull();

 

@Query("select u from User u")

Stream<User> streamAllPaged(Pageable pageable);

Luồng có khả năng bao bọc các tài nguyên cơ bản dành riêng cho cửa hàng dữ liệu và do đó, phải đóng sau khi sử dụng. Bạn có thể đóng Luồng theo cách thủ công bằng cách sử dụng phương thức close () hoặc bằng cách sử dụng khối thử tài nguyên Java 7, như được minh họa trong ví dụ sau:

Ví dụ 24. Làm việc với Luồng <T> dẫn đến khối thử tài nguyên

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {

  stream.forEach(…);

}

Không phải tất cả các mô-đun Dữ liệu mùa xuân hiện hỗ trợ Luồng Stream<T> như một kiểu trả về.

4.4.9. Kết quả truy vấn không đồng bộ

Bạn có thể chạy các truy vấn kho lưu trữ một cách không đồng bộ bằng cách sử dụng khả năng chạy phương thức không đồng bộ của Spring. Điều này có nghĩa là phương thức trả về ngay lập tức khi được gọi trong khi truy vấn thực sự xảy ra trong một tác vụ đã được gửi đến Spring TaskExecutor. Các truy vấn không đồng bộ khác với các truy vấn phản ứng và không được trộn lẫn. Xem tài liệu dành riêng cho cửa hàng để biết thêm chi tiết về hỗ trợ phản ứng. Ví dụ sau cho thấy một số truy vấn không đồng bộ:

@Async

Future<User> findByFirstname(String firstname);   (1)           

 

@Async

CompletableFuture<User> findOneByFirstname(String firstname); (2)

 

@Async

ListenableFuture<User> findOneByLastname(String lastname);    ” (3)

(1)    Sử dụng java.util.concurrent.Future làm kiểu trả về.

(2)    Sử dụng Java 8 java.util.concurrent.CompletableFuture làm kiểu trả về.

Sử dụng org.springframework.util.concurrent.ListenableFuture làm kiểu trả về.






4.5. Tạo phiên bản kho lưu trữ

Phần này trình bày cách tạo các phiên bản và định nghĩa bean cho các giao diện kho lưu trữ đã xác định. Một cách để làm điều đó là sử dụng không gian tên Spring được vận chuyển cùng với mỗi mô-đun Dữ liệu mùa xuân hỗ trợ cơ chế kho lưu trữ, mặc dù chúng tôi thường khuyên bạn nên sử dụng cấu hình Java.

4.5.1. Cấu hình XML

Mỗi mô-đun Dữ liệu mùa xuân bao gồm một repositoriesphần tử cho phép bạn xác định gói cơ sở mà Spring quét cho bạn, như được minh họa trong ví dụ sau:

Ví dụ 25. Bật kho lưu trữ Dữ liệu mùa xuân qua XML
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/data/jpa"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <repositories base-package="com.acme.repositories" />

</beans:beans>

Trong ví dụ trước, Spring được hướng dẫn quét com.acme.repositoriesvà tất cả các gói con của nó để tìm các giao diện mở rộng Repositoryhoặc một trong các giao diện con của nó. Đối với mỗi giao diện được tìm thấy, cơ sở hạ tầng đăng ký công nghệ bền vững cụ thể FactoryBeanđể tạo ra các proxy thích hợp xử lý các lệnh gọi của các phương thức truy vấn. Mỗi bean được đăng ký dưới tên bean có nguồn gốc từ tên giao diện, vì vậy một giao diện của UserRepositorysẽ được đăng ký theo userRepositoryTên đậu cho các giao diện kho lưu trữ lồng nhau được bắt đầu bằng tên loại bao quanh của chúng. Các base-packagethuộc tính cho phép ký tự đại diện để bạn có thể xác định một mô hình của gói quét.

Sử dụng bộ lọc

Theo mặc định, cơ sở hạ tầng chọn mọi giao diện mở rộng Repositorygiao diện phụ dành riêng cho công nghệ bền bỉ nằm trong gói cơ sở đã định cấu hình và tạo một cá thể bean cho nó. Tuy nhiên, bạn có thể muốn kiểm soát chi tiết hơn đối với giao diện nào có các phiên bản bean được tạo cho chúng. Để làm như vậy, hãy sử dụng <include-filter />và <exclude-filter />các phần tử bên trong <repositories />phần tử. Ngữ nghĩa hoàn toàn tương đương với các phần tử trong không gian tên ngữ cảnh của Spring. Để biết chi tiết, hãy xem tài liệu tham khảo Spring cho các yếu tố này.

Ví dụ: để loại trừ một số giao diện nhất định khỏi việc khởi tạo dưới dạng bean kho lưu trữ, bạn có thể sử dụng cấu hình sau:

Ví dụ 26. Sử dụng phần tử bộ lọc loại trừ
<repositories base-package="com.acme.repositories">
  <context:exclude-filter type="regex" expression=".*SomeRepository" />
</repositories>

Ví dụ trước loại trừ tất cả các giao diện kết thúc bằng SomeRepositoryviệc được khởi tạo.

4.5.2. Java Configuration

Bạn cũng có thể kích hoạt các cơ sở hạ tầng kho bằng cách sử dụng một cửa hàng cụ thể @Enable${store}Repositorieschú thích trên một cấu hình Java class.For giới thiệu về cấu hình dựa trên nền Java của container mùa xuân, xem JavaConfig trong tài liệu tham khảo mùa xuân .

Cấu hình mẫu để kích hoạt kho lưu trữ Dữ liệu mùa xuân giống như sau:

Ví dụ 27. Cấu hình kho lưu trữ dựa trên chú thích mẫu
@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {

  @Bean
  EntityManagerFactory entityManagerFactory() {
    // …
  }
}
Ví dụ trước sử dụng chú thích JPA cụ thể mà bạn sẽ thay đổi theo mô-đun cửa hàng mà bạn thực sự sử dụng EntityManagerFactory.

4.5.3. Sử dụng độc lập

Bạn cũng có thể sử dụng cơ sở hạ tầng kho lưu trữ bên ngoài vùng chứa Spring - ví dụ: trong môi trường CDI. hỗ trợ tàu với công nghệ bền bỉ cụ thể RepositoryFactorymà bạn có thể sử dụng, như sau:

Ví dụ 28. Cách sử dụng độc lập của nhà máy kho lưu trữ
RepositoryFactorySupport factory = … // Instantiate factory here
UserRepository repository = factory.getRepository(UserRepository.class);

4.6. Triển khai tùy chỉnh cho Kho lưu trữ dữ liệu mùa xuân

Spring Data cung cấp các tùy chọn khác nhau để tạo các phương thức truy vấn với ít mã hóa. Nhưng khi các tùy chọn đó không phù hợp với nhu cầu của bạn, bạn cũng có thể cung cấp triển khai tùy chỉnh của riêng mình cho các phương thức lưu trữ. Phần này mô tả cách thực hiện điều đó.

4.6.1. Tùy chỉnh kho lưu trữ riêng lẻ

Để làm phong phú thêm một kho lưu trữ với chức năng tùy chỉnh, trước tiên bạn phải xác định giao diện phân đoạn và triển khai cho chức năng tùy chỉnh, như sau:

Ví dụ 29. ​​Giao diện cho chức năng kho lưu trữ tùy chỉnh
interface CustomizedUserRepository {
  void someCustomMethod(User user);
}
Ví dụ 30. Triển khai chức năng kho lưu trữ tùy chỉnh
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

  public void someCustomMethod(User user) {
    // Your custom implementation
  }
}
Phần quan trọng nhất của tên lớp tương ứng với giao diện phân mảnh là hậu tố Impl.

Bản thân việc triển khai không phụ thuộc vào Spring Data và có thể là một Spring bean thông thường. Do đó, bạn có thể sử dụng hành vi tiêm phụ thuộc tiêu chuẩn để đưa các tham chiếu đến các bean khác (chẳng hạn như a JdbcTemplate), tham gia vào các khía cạnh, v.v.

Sau đó, bạn có thể để giao diện kho lưu trữ của mình mở rộng giao diện phân mảnh, như sau:

Ví dụ 31. Các thay đổi đối với giao diện kho lưu trữ của bạn
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {

  // Declare query methods here
}

Mở rộng giao diện phân mảnh với giao diện kho lưu trữ của bạn kết hợp CRUD và chức năng tùy chỉnh và cung cấp nó cho khách hàng.

Kho lưu trữ Dữ liệu mùa xuân được triển khai bằng cách sử dụng các phân đoạn tạo thành một thành phần kho lưu trữ. Các phân đoạn là kho lưu trữ cơ sở, các khía cạnh chức năng (chẳng hạn như QueryDsl ) và các giao diện tùy chỉnh cùng với các triển khai của chúng. Mỗi lần bạn thêm một giao diện vào giao diện kho lưu trữ của mình, bạn sẽ nâng cao thành phần bằng cách thêm một phân đoạn. Kho lưu trữ cơ sở và các triển khai khía cạnh của kho lưu trữ được cung cấp bởi mỗi mô-đun Dữ liệu mùa xuân.

Ví dụ sau đây cho thấy các giao diện tùy chỉnh và cách triển khai của chúng:

Ví dụ 32. Các phân đoạn với cách triển khai của chúng
interface HumanRepository {
  void someHumanMethod(User user);
}

class HumanRepositoryImpl implements HumanRepository {

  public void someHumanMethod(User user) {
    // Your custom implementation
  }
}

interface ContactRepository {

  void someContactMethod(User user);

  User anotherContactMethod(User user);
}

class ContactRepositoryImpl implements ContactRepository {

  public void someContactMethod(User user) {
    // Your custom implementation
  }

  public User anotherContactMethod(User user) {
    // Your custom implementation
  }
}

Ví dụ sau cho thấy giao diện cho một kho lưu trữ tùy chỉnh mở rộng CrudRepository:

Ví dụ 33. Các thay đổi đối với giao diện kho lưu trữ của bạn
interface UserRepository extends CrudRepository<User, Long>, HumanRepository, ContactRepository {

  // Declare query methods here
}

Các kho lưu trữ có thể bao gồm nhiều triển khai tùy chỉnh được nhập theo thứ tự khai báo của chúng. Triển khai tùy chỉnh có mức độ ưu tiên cao hơn so với các khía cạnh triển khai cơ sở và kho lưu trữ. cùng một phương pháp chữ ký. Các phân đoạn kho lưu trữ không bị giới hạn để sử dụng trong một giao diện kho lưu trữ. Nhiều kho lưu trữ có thể sử dụng một giao diện phân mảnh, cho phép bạn sử dụng lại các tùy chỉnh trên các kho lưu trữ khác nhau.

Ví dụ sau cho thấy một phân đoạn kho lưu trữ và cách triển khai của nó:

Ví dụ 34. Ghi đè các đoạn save(…)
interface CustomizedSave<T> {
  <S extends T> S save(S entity);
}

class CustomizedSaveImpl<T> implements CustomizedSave<T> {

  public <S extends T> S save(S entity) {
    // Your custom implementation
  }
}

Ví dụ sau đây cho thấy một kho lưu trữ sử dụng phân đoạn kho lưu trữ trước:

Ví dụ 35. Giao diện kho lưu trữ tùy chỉnh
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}

interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> {
}
Cấu hình

Nếu bạn sử dụng cấu hình không gian tên, cơ sở hạ tầng kho lưu trữ sẽ cố gắng tự động phát hiện các phân đoạn triển khai tùy chỉnh bằng cách quét các lớp bên dưới gói mà nó tìm thấy một kho lưu trữ. Các lớp này cần tuân theo quy ước đặt tên là thêm repository-impl-postfixthuộc tính của phần tử không gian tên vào tên giao diện phân mảnh. Postfix này mặc định là ImplVí dụ sau đây cho thấy một kho lưu trữ sử dụng postfix mặc định và một kho lưu trữ đặt giá trị tùy chỉnh cho postfix:

Ví dụ 36. Ví dụ về cấu hình
<repositories base-package="com.acme.repository" />

<repositories base-package="com.acme.repository" repository-impl-postfix="MyPostfix" />

Cấu hình đầu tiên trong ví dụ trước cố gắng tìm kiếm một lớp được gọi com.acme.repository.CustomizedUserRepositoryImplđể hoạt động như một triển khai kho lưu trữ tùy chỉnh. Ví dụ thứ hai cố gắng tra cứu com.acme.repository.CustomizedUserRepositoryMyPostfix.

Giải quyết sự mơ hồ

Nếu tìm thấy nhiều triển khai với tên lớp phù hợp trong các gói khác nhau, thì Spring Data sẽ sử dụng tên bean để xác định cái nào sẽ sử dụng.

Với hai triển khai tùy chỉnh sau cho phần CustomizedUserRepositorytrước đó, triển khai đầu tiên được sử dụng. Tên bean của nó là customizedUserRepositoryImpl, khớp với tên của giao diện phân mảnh ( CustomizedUserRepository) cộng với hậu tố Impl.

Ví dụ 37. Giải quyết các triển khai mơ hồ
package com.acme.impl.one;

class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

  // Your custom implementation
}
package com.acme.impl.two;

@Component("specialCustomImpl")
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

  // Your custom implementation
}

Nếu bạn chú thích UserRepositorygiao diện với @Component("specialCustom"), tên bean cộng Implsau đó khớp với tên được xác định cho việc triển khai kho lưu trữ trong com.acme.impl.twovà nó được sử dụng thay vì tên đầu tiên.

Đấu dây thủ công

Nếu triển khai tùy chỉnh của bạn chỉ sử dụng cấu hình dựa trên chú thích và tự động tạo, thì cách tiếp cận trước được hiển thị sẽ hoạt động tốt, vì nó được coi như bất kỳ Spring bean nào khác. Nếu bean phân đoạn thực thi của bạn cần đi dây đặc biệt, bạn có thể khai báo bean và đặt tên cho nó theo các quy ước được mô tả trong phần trước . Sau đó, cơ sở hạ tầng đề cập đến định nghĩa bean được xác định thủ công theo tên thay vì tạo ra chính nó. Ví dụ sau đây cho thấy cách bắt đầu triển khai tùy chỉnh theo cách thủ công:

Ví dụ 38. Đấu dây thủ công cho các triển khai tùy chỉnh
<repositories base-package="com.acme.repository" />

<beans:bean id="userRepositoryImpl" class="…">
  <!-- further configuration -->
</beans:bean>

4.6.2. Tùy chỉnh Kho lưu trữ Cơ sở

Cách tiếp cận được mô tả trong phần trước yêu cầu tùy chỉnh từng giao diện kho lưu trữ khi bạn muốn tùy chỉnh hành vi của kho lưu trữ cơ sở để tất cả các kho đều bị ảnh hưởng. Thay vào đó, để thay đổi hành vi cho tất cả các kho, bạn có thể tạo một triển khai mở rộng lớp cơ sở kho lưu trữ dành riêng cho công nghệ bền bỉ. Sau đó, lớp này hoạt động như một lớp cơ sở tùy chỉnh cho các proxy của kho lưu trữ, như được hiển thị trong ví dụ sau:

Ví dụ 39. Lớp cơ sở kho lưu trữ tùy chỉnh
class MyRepositoryImpl<T, ID>
  extends SimpleJpaRepository<T, ID> {

  private final EntityManager entityManager;

  MyRepositoryImpl(JpaEntityInformation entityInformation,
                          EntityManager entityManager) {
    super(entityInformation, entityManager);

    // Keep the EntityManager around to used from the newly introduced methods.
    this.entityManager = entityManager;
  }

  @Transactional
  public <S extends T> S save(S entity) {
    // implementation goes here
  }
}
Lớp cần có một phương thức khởi tạo của siêu lớp mà việc triển khai nhà máy kho lưu trữ dành riêng cho cửa hàng sử dụng. Nếu lớp cơ sở của kho lưu trữ có nhiều hàm tạo, hãy ghi đè lớp lấy dấu EntityInformationcộng với một đối tượng cơ sở hạ tầng cụ thể lưu trữ (chẳng hạn như một EntityManagerhoặc một lớp mẫu).

Bước cuối cùng là làm cho cơ sở hạ tầng Dữ liệu mùa xuân nhận thức được lớp cơ sở của kho lưu trữ tùy chỉnh. Trong cấu hình Java, bạn có thể làm như vậy bằng cách sử dụng repositoryBaseClassthuộc tính của @Enable${store}Repositorieschú thích, như được hiển thị trong ví dụ sau:

Ví dụ 40. Cấu hình lớp cơ sở kho lưu trữ tùy chỉnh bằng JavaConfig
@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }

Một thuộc tính tương ứng có sẵn trong không gian tên XML, như được hiển thị trong ví dụ sau:

Ví dụ 41. Cấu hình lớp cơ sở kho lưu trữ tùy chỉnh bằng XML
<repositories base-package="com.acme.repository"
     base-class="….MyRepositoryImpl" />

4.7. Sự kiện xuất bản từ Gốc tổng hợp

Các thực thể được quản lý bởi kho lưu trữ là các gốc tổng hợp. Trong ứng dụng Thiết kế theo hướng miền, các gốc tổng hợp này thường xuất bản các sự kiện miền. Spring Data cung cấp một chú thích được gọi là @DomainEventsmà bạn có thể sử dụng trên một phương thức gốc tổng hợp của mình để làm cho việc xuất bản đó trở nên dễ dàng nhất có thể, như được hiển thị trong ví dụ sau:

Ví dụ 42. Hiển thị các sự kiện miền từ một gốc tổng hợp
class AnAggregateRoot {

    @DomainEvents 
    Collection<Object> domainEvents() {
        // … return events you want to get published here
    }

    @AfterDomainEventPublication 
    void callbackMethod() {
       // … potentially clean up domain events list
    }
}
Phương thức sử dụng @DomainEventscó thể trả về một cá thể sự kiện đơn lẻ hoặc một tập hợp các sự kiện. Nó không được lấy bất kỳ đối số nào.
Sau khi tất cả các sự kiện đã được xuất bản, chúng tôi có một phương thức được chú thích với @AfterDomainEventPublication. Bạn có thể sử dụng nó để làm sạch danh sách các sự kiện sẽ được xuất bản (trong số các cách sử dụng khác).

Các phương pháp này được gọi là mỗi một thời điểm của dữ liệu Xuân kho save(…)saveAll(…)delete(…)hoặc deleteAll(…)các phương pháp được gọi là.

4.8. Tiện ích mở rộng dữ liệu mùa xuân

Phần này ghi lại một tập hợp các phần mở rộng Dữ liệu mùa xuân cho phép sử dụng Dữ liệu mùa xuân trong nhiều ngữ cảnh khác nhau. Hiện tại, hầu hết việc tích hợp đều hướng tới Spring MVC.

4.8.1. Phần mở rộng Querydsl

Querydsl là một khung công tác cho phép xây dựng các truy vấn giống SQL được nhập tĩnh thông qua API thông thạo của nó.

Một số mô-đun Dữ liệu mùa xuân cung cấp tích hợp với Querydsl thông qua QuerydslPredicateExecutor, như ví dụ sau cho thấy:

Ví dụ 43. Giao diện QuerydslPredicateExecutor
public interface QuerydslPredicateExecutor<T> {

  Optional<T> findById(Predicate predicate);  

  Iterable<T> findAll(Predicate predicate);   

  long count(Predicate predicate);            

  boolean exists(Predicate predicate);        

  // … more functionality omitted.
}
Tìm và trả về một thực thể phù hợp với Predicate.
Tìm và trả về tất cả các thực thể khớp với Predicate.
Trả về số thực thể khớp với Predicate.
Trả về liệu một thực thể phù hợp với Predicatetồn tại hay không.

Để sử dụng hỗ trợ Querydsl, hãy mở rộng QuerydslPredicateExecutortrên giao diện kho lưu trữ của bạn, như ví dụ sau cho thấy:

Ví dụ 44. Tích hợp truy vấndsl trên kho
interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {
}

Ví dụ trước cho phép bạn viết các truy vấn an toàn kiểu bằng cách sử dụng các phiên bản Querydsl Predicate, như ví dụ sau cho thấy:

Predicate predicate = user.firstname.equalsIgnoreCase("dave")
	.and(user.lastname.startsWithIgnoreCase("mathews"));

userRepository.findAll(predicate);

4.8.2. Hỗ trợ web

Các mô-đun Spring Data hỗ trợ mô hình lập trình kho lưu trữ với nhiều hỗ trợ web. Các thành phần liên quan đến web yêu cầu các JAR của Spring MVC phải ở trên đường dẫn classpath. Một số người trong số họ thậm chí còn cung cấp tích hợp với Spring HATEOAS . Nói chung, hỗ trợ tích hợp được bật bằng cách sử dụng @EnableSpringDataWebSupportchú thích trong lớp cấu hình JavaConfig của bạn, như ví dụ sau cho thấy:

Ví dụ 45. Bật hỗ trợ web Dữ liệu mùa xuân
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration {}

Các @EnableSpringDataWebSupportchú thích đăng ký một vài thành phần. Chúng ta sẽ thảo luận về những điều đó sau trong phần này. Nó cũng phát hiện Spring HATEOAS trên classpath và đăng ký các thành phần tích hợp (nếu có) cho nó.

Ngoài ra, nếu bạn sử dụng cấu hình XML, hãy đăng ký SpringDataWebConfigurationhoặc HateoasAwareSpringDataWebConfigurationdưới dạng Spring bean, như ví dụ sau cho thấy (cho SpringDataWebConfiguration):

Ví dụ 46. Bật hỗ trợ web Dữ liệu mùa xuân trong XML
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />

<!-- If you use Spring HATEOAS, register this one *instead* of the former -->
<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />
Hỗ trợ web cơ bản

Cấu hình hiển thị trong phần trước đăng ký một số thành phần cơ bản:

  • Sử dụng DomainClassConverterLớp để cho Spring MVC giải quyết các trường hợp của các lớp miền do kho lưu trữ quản lý từ các tham số yêu cầu hoặc biến đường dẫn.

  • HandlerMethodArgumentResolvertriển khai để cho Spring MVC giải quyết Pageablevà các Sortphiên bản từ các tham số yêu cầu.

  • Jackson Modules để loại bỏ / tuần tự hóa các loại như Pointvà Distance, hoặc lưu trữ các loại cụ thể, tùy thuộc vào Spring Data Module được sử dụng.

Sử dụng DomainClassConverterLớp học

Các DomainClassConverterlớp cho phép bạn sử dụng các loại tên miền trong Spring MVC phương pháp điều khiển chữ ký của bạn trực tiếp để bạn không cần phải tự tra cứu các trường hợp thông qua các kho lưu trữ, như ví dụ chương trình sau đây:

Ví dụ 47. Bộ điều khiển Spring MVC sử dụng các kiểu miền trong chữ ký phương thức
@Controller
@RequestMapping("/users")
class UserController {

  @RequestMapping("/{id}")
  String showUserForm(@PathVariable("id") User user, Model model) {

    model.addAttribute("user", user);
    return "userForm";
  }
}

Phương thức nhận Usertrực tiếp một cá thể và không cần tra cứu thêm. Cá thể có thể được giải quyết bằng cách cho phép Spring MVC chuyển đổi biến đường dẫn thành idkiểu của lớp miền trước và cuối cùng truy cập cá thể thông qua việc gọi findById(…)cá thể kho lưu trữ đã đăng ký cho kiểu miền.

Hiện tại, kho lưu trữ phải thực hiện CrudRepositoryđể đủ điều kiện được phát hiện để chuyển đổi.
HandlerMethodArgumentResolvers để Pagable và sắp xếp

Đoạn mã cấu hình được hiển thị trong phần trước cũng đăng ký một PageableHandlerMethodArgumentResolvercũng như một phiên bản của SortHandlerMethodArgumentResolverViệc đăng ký cho phép Pageablevà Sortlà đối số của phương thức bộ điều khiển hợp lệ, như ví dụ sau cho thấy:

Ví dụ 48. Sử dụng Pagable làm đối số phương thức bộ điều khiển
@Controller
@RequestMapping("/users")
class UserController {

  private final UserRepository repository;

  UserController(UserRepository repository) {
    this.repository = repository;
  }

  @RequestMapping
  String showUsers(Model model, Pageable pageable) {

    model.addAttribute("users", repository.findAll(pageable));
    return "users";
  }
}

Chữ ký của phương thức trước khiến Spring MVC cố gắng lấy một Pageablethể hiện từ các tham số yêu cầu bằng cách sử dụng cấu hình mặc định sau:

Bảng 1. Các thông số yêu cầu được đánh giá cho các Pageablephiên bản

page

Trang bạn muốn truy xuất. 0 được lập chỉ mục và mặc định là 0.

size

Kích thước của trang bạn muốn truy xuất. Mặc định là 20.

sort

Thuộc tính nên được sắp xếp theo định dạng property,property(,ASC|DESC)(,IgnoreCase)Hướng sắp xếp mặc định phân biệt chữ hoa chữ thường tăng dần. Sử dụng nhiều sorttham số nếu bạn muốn chuyển hướng hoặc phân biệt chữ hoa chữ thường - chẳng hạn ?sort=firstname&sort=lastname,asc&sort=city,ignorecase.

Để tùy chỉnh hành vi này, hãy đăng ký một bean triển khai PageableHandlerMethodArgumentResolverCustomizergiao diện hoặc SortHandlerMethodArgumentResolverCustomizergiao diện tương ứng. customize()Phương thức của nó được gọi, cho phép bạn thay đổi cài đặt, như ví dụ sau cho thấy:

@Bean SortHandlerMethodArgumentResolverCustomizer sortCustomizer() {
    return s -> s.setPropertyDelimiter("<-->");
}

Nếu việc thiết lập các thuộc tính của một cái hiện có MethodArgumentResolverkhông đủ cho mục đích của bạn, hãy mở rộng một trong hai SpringDataWebConfigurationhoặc tương đương hỗ trợ HATEOAS, ghi đè pageableResolver()hoặc sortResolver()các phương thức và nhập tệp cấu hình tùy chỉnh của bạn thay vì sử dụng @Enablechú thích.

Nếu bạn cần nhiều Pageablehoặc nhiều Sortphiên bản được giải quyết từ yêu cầu (ví dụ: đối với nhiều bảng), bạn có thể sử dụng @Qualifierchú thích của Spring để phân biệt bảng này với bảng khác. Các tham số yêu cầu sau đó phải được bắt đầu bằng ${qualifier}_Ví dụ sau cho thấy chữ ký phương thức kết quả:

String showUsers(Model model,
      @Qualifier("thing1") Pageable first,
      @Qualifier("thing2") Pageable second) { … }

Bạn phải nhập cư thing1_pagething2_pagev.v.

Giá trị mặc định Pageableđược truyền vào phương thức tương đương với a PageRequest.of(0, 20), nhưng bạn có thể tùy chỉnh nó bằng cách sử dụng @PageableDefaultchú thích trên Pageabletham số.

Hỗ trợ Hypermedia cho Pageables

Spring HATEOAS cung cấp lớp mô hình đại diện ( PagedResources) cho phép làm phong phú nội dung của một Pagephiên bản với Pagesiêu dữ liệu cần thiết cũng như các liên kết để cho phép khách hàng dễ dàng điều hướng các trang. Việc chuyển đổi a Pagethành a PagedResourcesđược thực hiện bằng cách triển khai ResourceAssemblergiao diện Spring HATEOAS , được gọi là PagedResourcesAssemblerVí dụ sau đây cho thấy cách sử dụng một PagedResourcesAssemblerđối số phương thức bộ điều khiển làm đối số:

Ví dụ 49. Sử dụng một PagedResourcesAssembler làm đối số phương thức bộ điều khiển
@Controller
class PersonController {

  @Autowired PersonRepository repository;

  @RequestMapping(value = "/persons", method = RequestMethod.GET)
  HttpEntity<PagedResources<Person>> persons(Pageable pageable,
    PagedResourcesAssembler assembler) {

    Page<Person> persons = repository.findAll(pageable);
    return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
  }
}

Việc kích hoạt cấu hình, như được hiển thị trong ví dụ trước, cho phép nó PagedResourcesAssemblerđược sử dụng như một đối số của phương thức bộ điều khiển. Gọi toResources(…)vào nó có các tác dụng sau:

  • Nội dung của Pagetrở thành nội dung của PagedResourcescá thể.

  • Đối PagedResourcestượng được PageMetadatađính kèm một thể hiện và nó được cung cấp thông tin từ Pagebên dưới và bên dưới PageRequest.

  • Có PagedResourcesthể nhận prevvà nextliên kết được đính kèm, tùy thuộc vào trạng thái của trang. Các liên kết trỏ đến URI mà phương thức ánh xạ tới. Các tham số phân trang được thêm vào phương thức phù hợp với thiết lập của PageableHandlerMethodArgumentResolverđể đảm bảo các liên kết có thể được giải quyết sau này.

Giả sử chúng ta có 30 Personphiên bản trong cơ sở dữ liệu. Bây giờ bạn có thể kích hoạt một yêu cầu ( ) và xem đầu ra tương tự như sau:GET http://localhost:8080/persons

{ "links" : [ { "rel" : "next",
                "href" : "http://localhost:8080/persons?page=1&size=20" }
  ],
  "content" : [// 20 Person instances rendered here
  ],
  "pageMetadata" : {
    "size" : 20,
    "totalElements" : 30,
    "totalPages" : 2,
    "number" : 0
  }
}

Trình hợp dịch đã tạo ra đúng URI và cũng chọn cấu hình mặc định để phân giải các tham số thành một Pageableyêu cầu sắp tới. Điều này có nghĩa là, nếu bạn thay đổi cấu hình đó, các liên kết sẽ tự động tuân theo thay đổi. Theo mặc định, trình hợp dịch trỏ đến phương thức điều khiển mà nó được gọi, nhưng bạn có thể tùy chỉnh điều đó bằng cách chuyển một tùy chỉnh Linkđược sử dụng làm cơ sở để xây dựng các liên kết phân trang, PagedResourcesAssembler.toResource(…)phương thức này sẽ làm quá tải phương thức.

Mô-đun Spring Data Jackson

Mô-đun cốt lõi và một số mô-đun cụ thể trong cửa hàng, đi kèm với một bộ Mô-đun Jackson cho các loại, như org.springframework.data.geo.Distancevà org.springframework.data.geo.Point, được sử dụng bởi miền Dữ liệu Mùa xuân.
Các Mô-đun đó được nhập sau khi hỗ trợ web được kích hoạt và com.fasterxml.jackson.databind.ObjectMapperkhả dụng.

Trong quá trình khởi tạo SpringDataJacksonModules, chẳng hạn như SpringDataJacksonConfiguration, được cơ sở hạ tầng thu nhận để các phần tử đã khai báo com.fasterxml.jackson.databind.Moduleđược cung cấp cho Jackson ObjectMapper.

Các hỗn hợp liên kết dữ liệu cho các loại miền sau được đăng ký bởi cơ sở hạ tầng chung.

org.springframework.data.geo.Distance
org.springframework.data.geo.Point
org.springframework.data.geo.Box
org.springframework.data.geo.Circle
org.springframework.data.geo.Polygon

Mô-đun riêng lẻ có thể cung cấp thêm SpringDataJacksonModules.
Vui lòng tham khảo phần cụ thể của cửa hàng để biết thêm chi tiết.

Hỗ trợ Web Databinding

Bạn có thể sử dụng các phép chiếu Dữ liệu mùa xuân (được mô tả trong Phép chiếu ) để ràng buộc tải trọng yêu cầu đến bằng cách sử dụng biểu thức JSONPath (yêu cầu biểu thức Jayway JsonPath hoặc XPath (yêu cầu XmlBeam ), như ví dụ sau cho thấy:

Ví dụ 50. Liên kết trọng tải HTTP sử dụng biểu thức JSONPath hoặc XPath
@ProjectedPayload
public interface UserPayload {

  @XBRead("//firstname")
  @JsonPath("$..firstname")
  String getFirstname();

  @XBRead("/lastname")
  @JsonPath({ "$.lastname", "$.user.lastname" })
  String getLastname();
}

Bạn có thể sử dụng kiểu được hiển thị trong ví dụ trước làm đối số phương thức của trình xử lý Spring MVC hoặc bằng cách sử dụng ParameterizedTypeReferencetrên một trong các phương thức của RestTemplateCác khai báo phương thức trước đó sẽ cố gắng tìm firstnamebất kỳ đâu trong tài liệu đã cho. Việc lastnametra cứu XML được thực hiện ở cấp cao nhất của tài liệu đến. Biến thể JSON của điều đó thử một cấp cao nhất lastnametrước tiên nhưng cũng cố gắng lastnamelồng trong một usertài liệu con nếu tài liệu trước đó không trả về giá trị. Bằng cách đó, các thay đổi trong cấu trúc của tài liệu nguồn có thể được giảm thiểu một cách dễ dàng mà không cần các máy khách gọi các phương thức tiếp xúc (thường là một nhược điểm của ràng buộc trọng tải dựa trên lớp).

Các phép chiếu lồng nhau được hỗ trợ như được mô tả trong Phép chiếu . Nếu phương thức trả về một kiểu phức tạp, không có giao diện, thì một Jackson ObjectMapperđược sử dụng để ánh xạ giá trị cuối cùng.

Đối với Spring MVC, các bộ chuyển đổi cần thiết được đăng ký tự động ngay khi @EnableSpringDataWebSupporthoạt động và các phụ thuộc bắt buộc có sẵn trên classpath. Để sử dụng với RestTemplate, hãy đăng ký ProjectingJackson2HttpMessageConverter(JSON) hoặc XmlBeamHttpMessageConvertertheo cách thủ công.

Để biết thêm thông tin, hãy xem ví dụ về phép chiếu web trong kho lưu trữ Ví dụ về dữ liệu mùa xuân chuẩn .

Hỗ trợ Web Querydsl

Đối với những cửa hàng có tích hợp QueryDSL , bạn có thể lấy truy vấn từ các thuộc tính có trong một Requestchuỗi truy vấn.

Hãy xem xét chuỗi truy vấn sau:

?firstname=Dave&lastname=Matthews

Với Userđối tượng từ các ví dụ trước, bạn có thể giải quyết một chuỗi truy vấn thành giá trị sau bằng cách sử dụng QuerydslPredicateArgumentResolver, như sau:

QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))
Tính năng này sẽ tự động được bật, cùng với @EnableSpringDataWebSupport, khi Querydsl được tìm thấy trên classpath.

Thêm một @QuerydslPredicatevào chữ ký phương thức cung cấp một phiên bản sẵn sàng để sử dụng Predicate, mà bạn có thể chạy bằng cách sử dụng QuerydslPredicateExecutor.

Thông tin kiểu thường được giải quyết từ kiểu trả về của phương thức. Vì thông tin đó không nhất thiết phải khớp với loại miền, nên bạn có thể sử dụng rootthuộc tính của QuerydslPredicate.

Ví dụ sau đây cho thấy cách sử dụng @QuerydslPredicatetrong một chữ ký phương thức:

@Controller
class UserController {

  @Autowired UserRepository repository;

  @RequestMapping(value = "/", method = RequestMethod.GET)
  String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate,    
          Pageable pageable, @RequestParam MultiValueMap<String, String> parameters) {

    model.addAttribute("users", repository.findAll(predicate, pageable));

    return "index";
  }
}
Giải quyết các đối số chuỗi truy vấn thành đối sánh Predicatecho User.

Ràng buộc mặc định như sau:

  • Objecttrên các thuộc tính đơn giản như eq.

  • Objecttrên bộ sưu tập như thuộc tính như contains.

  • Collectiontrên các thuộc tính đơn giản như in.

Bạn có thể tùy chỉnh các ràng buộc đó thông qua bindingsthuộc tính của @QuerydslPredicatehoặc bằng cách sử dụng Java 8 default methodsvà thêm QuerydslBinderCustomizerphương thức vào giao diện kho lưu trữ, như sau:

interface UserRepository extends CrudRepository<User, String>,
                                 QuerydslPredicateExecutor<User>,                
                                 QuerydslBinderCustomizer<QUser> {               

  @Override
  default void customize(QuerydslBindings bindings, QUser user) {

    bindings.bind(user.username).first((path, value) -> path.contains(value))    
    bindings.bind(String.class)
      .first((StringPath path, String value) -> path.containsIgnoreCase(value)); 
    bindings.excluding(user.password);                                           
  }
}
QuerydslPredicateExecutorcung cấp quyền truy cập vào các phương pháp tìm cụ thể cho Predicate.
QuerydslBinderCustomizerđược định nghĩa trên giao diện kho lưu trữ được tự động chọn và các phím tắt @QuerydslPredicate(bindings=…​).
Xác định ràng buộc cho thuộc usernametính là một containsràng buộc đơn giản .
Xác định ràng buộc mặc định cho Stringcác thuộc tính là containsđối sánh không phân biệt chữ hoa chữ thường .
Loại trừ passwordtài sản khỏi Predicategiải pháp.
Bạn có thể đăng ký một QuerydslBinderCustomizerDefaultsbean giữ các ràng buộc Querydsl mặc định trước khi áp dụng các ràng buộc cụ thể từ kho lưu trữ hoặc @QuerydslPredicate.

4.8.3. Người phổ biến kho lưu trữ

Nếu bạn làm việc với mô-đun Spring JDBC, có thể bạn đã quen với việc hỗ trợ điền DataSourcetập lệnh SQL. Một phần trừu tượng tương tự có sẵn ở cấp kho lưu trữ, mặc dù nó không sử dụng SQL làm ngôn ngữ định nghĩa dữ liệu vì nó phải độc lập với cửa hàng. Do đó, các nhà phổ biến hỗ trợ XML (thông qua sự trừu tượng hóa OXM của Spring) và JSON (thông qua Jackson) để xác định dữ liệu để đưa vào các kho lưu trữ.

Giả sử bạn có một tệp được gọi data.jsonvới nội dung sau:

Ví dụ 51. Dữ liệu được định nghĩa trong JSON
[ { "_class" : "com.acme.Person",
 "firstname" : "Dave",
  "lastname" : "Matthews" },
  { "_class" : "com.acme.Person",
 "firstname" : "Carter",
  "lastname" : "Beauford" } ]

Bạn có thể điền kho lưu trữ của mình bằng cách sử dụng các phần tử phổ biến của không gian tên kho lưu trữ được cung cấp trong Spring Data Commons. Để điền dữ liệu trước vào của bạn PersonRepository, hãy khai báo một công cụ phổ biến tương tự như sau:

Ví dụ 52. Tuyên bố một nhà phổ biến kho lưu trữ Jackson
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:repository="http://www.springframework.org/schema/data/repository"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/repository
    https://www.springframework.org/schema/data/repository/spring-repository.xsd">

  <repository:jackson2-populator locations="classpath:data.json" />

</beans>

Khai báo trước làm cho data.jsontệp được đọc và giải mã bởi Jackson ObjectMapper.

Loại đối tượng JSON không được quản lý được xác định bằng cách kiểm tra _classthuộc tính của tài liệu JSON. Cơ sở hạ tầng cuối cùng sẽ chọn kho lưu trữ thích hợp để xử lý đối tượng đã được giải mã.

Thay vào đó, để sử dụng XML để xác định dữ liệu mà các kho lưu trữ sẽ được điền vào, bạn có thể sử dụng unmarshaller-populatorphần tử. Bạn định cấu hình nó để sử dụng một trong các tùy chọn bộ điều phối XML có sẵn trong Spring OXM. Xem tài liệu tham khảo Spring để biết thêm chi tiết. Ví dụ sau đây cho thấy cách bỏ quản lý một người phổ biến kho lưu trữ với JAXB:

Ví dụ 53. Khai báo phổ biến kho lưu trữ giải nén (sử dụng JAXB)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:repository="http://www.springframework.org/schema/data/repository"
  xmlns:oxm="http://www.springframework.org/schema/oxm"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/repository
    https://www.springframework.org/schema/data/repository/spring-repository.xsd
    http://www.springframework.org/schema/oxm
    https://www.springframework.org/schema/oxm/spring-oxm.xsd">

  <repository:unmarshaller-populator locations="classpath:data.json"
    unmarshaller-ref="unmarshaller" />

  <oxm:jaxb2-marshaller contextPath="com.acme" />

</beans>

5. Tài liệu Tham khảo





6.1: giới thiệu

- Phn này mô t nhng điu cơ bn v cu hình Spring Data JPA thông qua:

1. Spring Namespace

2. Annotation-based Configuration

6.1.1: Spring Namespace

- Mô-đun JPA của Dữ liệu spring chứa một namespace tùy chỉnh cho phép xác định các bean lưu trữ. Nó cũng chứa một số tính năng và thuộc tính phần tử đặc biệt đối với JPA. Nói chung, kho lưu trữ JPA có thể được thiết lập bằng cách sử dụng phần tử repositories, như thể hiện trong ví dụ sau:

+ Ví dụ 1: Thiết lập kho lưu trữ JPA bằng cách sử dụng namespace



- Sử dụng phần tử repositories tra cứu Spring Data repositories như được mô tả trong  “Creating Repository Instances”. Ngoài ra, nó còn kích hoạt bản dịch persistence exception cho tất cả các bean được chú thích bằng @Repository, để cho phép các trường hợp ngoại lệ được ném bởi các nhà cung cấp persistence JPA được chuyển đổi thành DataAccessException hệ thống phân cấp của Spring .

- Thuộc tính Custom Namespace

+ Ngoài các thuộc tính mặc định của phần tử repositories, namespace  JPA cung cấp các thuộc tính bổ sung để cho phép bạn kiểm soát chi tiết hơn việc thiết lập repositories:

+ Các thuộc tính JPA tùy chỉnh cụ thể của phần tử repository

1. entity-manager-factory-ref: Rõ ràng dây EntityManagerFactory sẽ được sử dụng với các repositories được phát hiện bởi phần tử kho lưu trữ. Thường được sử dụng nếu nhiều beans EntityManagerFactory được sử dụng trong ứng dụng. Nếu không được cấu hình, dữ liệu Spring sẽ tự động tìm kiếm Bean EntityManagerFactory với tên EntityManagerFactory trong ApplicationContext.

2. transaction-manager-ref: Cấm rõ ràng planfilTransactionManager sẽ được sử dụng với các repositories được phát hiện bởi phần tử repositories. Thông thường chỉ cần thiết nếu nhiều người quản lý giao dịch hoặc các loại beans EntityManagerFactory đã được cấu hình. Mặc định cho một nền tảng platformTransaction được xác định bên trong ứng dụng hiện tại.

6.1.2: Cấu hình dựa trên chú thích

- Hỗ trợ Spring Data JPA repositories có thể được kích hoạt không chỉ thông qua namespace XML mà còn bằng cách sử dụng chú thích thông qua JavaConfig, như thể hiện trong ví dụ sau:



6.1.3: Bootstrap Model

- Theo mặc định, JPA repositories của spring là spring bean mặc định. Họ là singleton phạm vi và eagerly initialized. Trong quá trình khởi động, họ đã tương tác với JPA EntityManager để xác minh và mục đích phân tích siêu dữ liệu. Spring Framework hỗ trợ việc khởi tạo JPA EntityManagerFactory trong một luồng nền vì quá trình đó thường chiếm một lượng đáng kể thời gian khởi động trong một ứng dụng spring. Để sử dụng việc khởi tạo nền đó một cách hiệu quả, chúng ta cần đảm bảo rằng các kho lưu trữ JPA được khởi tạo càng muộn càng tốt.

- Kể từ Spring Data JPA 2.1, giờ đây bạn có thể định cấu hình BootstrapMode (thông qua chú thích @EnableJpaRepositories hoặc không gian tên XML) nhận các giá trị sau:

+ DEFAULT: Các repository được khởi tạo nhanh chóng trừ khi được chú thích rõ ràng bằng @Lazy. lazification chỉ có hiệu lực nếu không có bean máy khách nào cần một thể hiện của repository vì điều đó sẽ yêu cầu khởi tạo bean repository.

+ LAZY: Hoàn toàn tuyên bố tất cả các repository beans lazy và cũng gây ra các proxy khởi tạo lazy được tạo ra để được tiêm vào bean máy khách. Điều đó có nghĩa là, các repository đó sẽ không được khởi tạo nếu Bean Client chỉ đơn giản là lưu trữ thể hiện trong một trường và không sử dụng kho lưu trữ trong quá trình khởi tạo. Các trường hợp repository sẽ được khởi tạo và xác minh khi tương tác đầu tiên với repository.

+ DEFERRED: Về cơ bản, phương thức hoạt động giống như LAZY, nhưng kích hoạt khởi tạo repository để đáp ứng với ContextRefreshedEvent để repository được xác minh trước khi ứng dụng khởi động hoàn toàn.

6.2: Thực thể tồn tại

- Phần này mô tả cách persist (lưu) các thực thể với Spring Data JPA.

6.2.1: Lưu entities

- Lưu một entity có thể được thực hiện với phương thức CrudRepository.Save (...). Nó vẫn tồn tại hoặc hợp nhất các thực thể đã cho bằng cách sử dụng JPA EntityManager cơ bản. Nếu entity chưa được kéo dài, JPA dữ liệu Spring đã lưu thực thể với một lệnh gọi phương thức EntityManager.Persist (...). Nếu không, nó gọi phương thức EntityManager.Merge (...).

- Cách phát triển trạng thái entity

1. Version-Property and Id-Property inspection (default): Theo mặc định, Spring Data JPA mặc định, JPA kiểm tra trước nếu có một thuộc tính phiên bản của loại không nguyên thủy. Nếu có, thực thể được coi là mới nếu giá trị của tài sản đó là null. Nếu không có một phiên bản, JPA, hãy kiểm tra thuộc tính định danh của entity đã cho. Nếu thuộc tính Định danh là NULL, thì entity được coi là mới. Nếu không, nó được coi là không mới.

2. Implementing PersistableNếu một entity triển khai Persistable, Spring Data JPA sẽ ủy quyền phát hiện mới cho phương thức isNew (…) của entity.

3. Implementing EntityInformation: Bạn có thể tùy chỉnh trừu tượng hóa thực tế được sử dụng trong triển khai SimpleJpareputory bằng cách tạo một phân lớp của JParepositoryFactory và ghi đè phương thức GetEtityInFormation (...) cho phù hợp. Sau đó, bạn phải đăng ký thực hiện tùy chỉnh của JParepositoryFactory như một spring bean. Lưu ý rằng điều này sẽ hiếm khi cần thiết.

- Ví dụ 3. Một lớp cơ sở cho các entity có số nhận dạng được gán theo cách thủ công



6.3: Phương thức truy vấn

- Phần này mô tả các cách khác nhau để tạo truy vấn với Spring Data JPA.

6.3.1: Các cách tra cứu và truy vấn

- Mô-đun JPA hỗ trợ xác định truy vấn theo cách thủ công dưới dạng Chuỗi hoặc bắt nguồn từ tên phương thức.

- Các truy vấn có nguồn gốc với các vị từ IsStartingWith, startwith, startswith, isendingwith, endingwith, endswith, isnotcontained, notcontained, notcontains, iscontains, iscontaing, chứa các đối số tương ứng cho các truy vấn này sẽ được vệ sinh. Điều này có nghĩa là nếu các đối số thực sự chứa các ký tự được coi là như đại diện như những đại diện này sẽ được thoát ra để chúng chỉ khớp với tên gọi. Ký tự thoát được sử dụng có thể được cấu hình bằng cách đặt Escapecharacter của chú thích @enablejparepositoritories.

- Truy vấn đã khai báo

+ Mặc dù nhận được truy vấn có nguồn gốc từ tên phương thức khá tiện lợi, nhưng người ta có thể phải đối mặt với tình huống trong đó trình phân tích cú pháp tên phương thức không hỗ trợ từ khóa người ta muốn sử dụng hoặc tên phương thức sẽ không cần thiết xấu xí. Vì vậy, bạn có thể sử dụng JPA có tên Truy vấn thông qua quy ước đặt tên (xem bằng JPA có tên Truy vấn để biết thêm thông tin) hoặc thay vì chú thích phương thức truy vấn của bạn với @Query (xem bằng @Query để biết chi tiết).

6.3.2: Tạo truy vấn

- Nói chung, cơ chế tạo truy vấn cho JPA hoạt động như được mô tả trong “Phương thức truy vấn”. Ví dụ sau đây cho thấy phương thức truy vấn JPA chuyển thành:

- Ví dụ 57. Tạo truy vấn từ tên phương thức



- Bảng sau đây mô tả các từ khóa được hỗ trợ cho JPA và phương pháp chứa từ khóa đó sẽ dịch thành:




6.3.3: Sử dụng truy vấn có tên JPA

- Định nghĩa truy vấn được đặt tên XML

+ Để sử dụng cấu hình XML, hãy thêm phần tử <named-query/> cần thiết vào tệp cấu hình JPA ORM.XML nằm trong thư mục Meta-INF của đường dẫn lớp của bạn. Tự động gọi các truy vấn được đặt tên được kích hoạt bằng cách sử dụng một số quy ước đặt tên xác định.

- Ví dụ: Cấu hình truy vấn có tên XML



- Truy vấn có một tên đặc biệt được sử dụng để giải quyết nó trong thời gian chạy.

- Cấu hình dựa trên chú thích

+ Cấu hình dựa trên chú thích có ưu điểm là không cần chỉnh sửa tệp cấu hình khác, giảm nỗ lực bảo trì. Bạn trả tiền cho lợi ích đó bằng cách cần phải biên dịch lại lớp miền của mình cho mọi khai báo truy vấn mới.

- Ví dụ: Cấu hình truy vấn được đặt tên dựa trên chú thích



- Khai báo interfaces

- Để cho phép các truy vấn được đặt tên này, hãy chỉ định UserRepository như sau:



- Spring data cố gắng giải quyết cuộc gọi đến các phương thức này vào truy vấn có tên, bắt đầu bằng tên đơn giản của lớp miền được định cấu hình, theo sau là tên phương thức được phân tách bằng dấu chấm. Vì vậy, ví dụ trước sẽ sử dụng các truy vấn được đặt tên được xác định trước đó thay vì cố gắng tạo truy vấn từ tên phương thức.

6.3.4: Sử dụng @Query

- Sử dụng các truy vấn được đặt tên để khai báo các truy vấn cho các thực thể là một cách tiếp cận hợp lệ và hoạt động tốt cho một số lượng nhỏ truy vấn. Khi bản thân truy vấn được gắn với phương thức Java chạy chúng, bạn thực sự có thể liên kết chúng trực tiếp bằng cách sử dụng Chú thích JPA @Query của JPA thay vì chú thích chúng với lớp miền. Điều này giải phóng lớp miền từ thông tin cụ thể bền bỉ và đồng định vị truy vấn vào giao diện kho lưu trữ.

- Các truy vấn được chú thích cho phương thức truy vấn được ưu tiên hơn các truy vấn được xác định bằng @NamedQuery hoặc các truy vấn được đặt tên được khai báo trong orm.xml.

- Ví dụ sau cho thấy một truy vấn được tạo bằng chú thích @Query:



- Sử dụng biểu thức LIKE nâng cao

- Cơ chế chạy truy vấn cho các truy vấn được xác định theo cách thủ công được tạo bằng @Query cho phép định nghĩa các biểu thức LIKE nâng cao bên trong định nghĩa truy vấn, như được hiển thị trong ví dụ sau:



- Trong ví dụ trước đó, ký tự phân cách tương tự (%) được nhận dạng và truy vấn được chuyển đổi thành Truy vấn JPQL hợp lệ (xóa%). Khi chạy truy vấn, tham số được chuyển đến cuộc gọi phương thức được tăng cường với mẫu như được nhận dạng trước đó.

- Native Queries

- Chú thích @Query cho phép chạy các truy vấn gốc bằng cách đặt cờ nativeQuery thành true, như được hiển thị trong ví dụ sau:



- Ví dụ: Khai báo các truy vấn đếm gốc để phân trang tại phương thức truy vấn bằng cách sử dụng @Query



- Cách tiếp cận tương tự cũng hoạt động với các truy vấn gốc được đặt tên, bằng cách thêm hậu tố .count vào bản sao truy vấn của bạn. Tuy nhiên, bạn có thể cần đăng ký ánh xạ tập kết quả cho truy vấn đếm của mình.

6.3.5: Sử dụng Sort

- Sorting  có thể được thực hiện bằng cách cung cấp một công ty hoặc bằng cách sử dụng Sorting  trực tiếp. Các thuộc tính thực sự được sử dụng trong các trường hợp sắp xếp theo thứ tự cần khớp với mô hình miền của bạn, điều đó có nghĩa là chúng cần phải giải quyết thành một thuộc tính hoặc một bí danh được sử dụng trong truy vấn. JPQL xác định đây là biểu thức đường dẫn trường trạng thái.

- Tuy nhiên, sử dụng sorting cùng với @Query cho phép bạn lén lút trong các phiên bản đơn hàng không được kiểm tra có chứa các hàm trong mệnh đề theo thứ tự theo thứ tự. Điều này là có thể bởi vì thứ tự được gắn vào chuỗi truy vấn đã cho. Theo mặc định, jpa dữ liệu lò xo từ chối bất kỳ trường hợp đơn hàng nào có chứa các lệnh gọi hàm, nhưng bạn có thể sử dụng jpasort.Unsafe để thêm lệnh đặt hàng không an toàn.

- Ví dụ sau sử dụng Sắp xếp và JpaSort, bao gồm một tùy chọn không an toàn trên JpaSort:



6.3.6: Sử dụng các tham số được đặt tên

- Theo mặc định, JPA dữ liệu Spring sử dụng ràng buộc tham số dựa trên vị trí, như được mô tả trong tất cả các ví dụ trước đó. Điều này làm cho các phương thức truy vấn một chút dễ bị lỗi khi tái cấu trúc về vị trí tham số. Để giải quyết vấn đề này, bạn có thể sử dụng chú thích @param để cung cấp một tham số phương thức một tên bê tông và ràng buộc tên trong truy vấn, như thể hiện trong ví dụ sau:



6.3.7: Sử dụng biểu thức SpEL

- Kể từ lần phát hành JPA của Spring Data 1.4, chúng tôi hỗ trợ việc sử dụng các biểu thức mẫu SPEL bị hạn chế trong các truy vấn được xác định theo cách thủ công được xác định bằng @Query. Khi truy vấn được chạy, các biểu thức này được đánh giá đối với một tập hợp các biến được xác định trước. Dữ liệu lò xo JPA hỗ trợ một biến được gọi là EntityName. Cách sử dụng của nó được chọn x từ # {# EntityName} x. Nó chèn các entername của loại miền được liên kết với kho lưu trữ đã cho. EntityName được giải quyết như sau: Nếu loại miền đã đặt thuộc tính tên trên chú thích @Etnity, nó được sử dụng. Nếu không, tên lớp đơn giản của loại miền được sử dụng.

- Ví dụ sau minh họa một trường hợp sử dụng cho biểu thức # {# entityName} trong chuỗi truy vấn mà bạn muốn xác định giao diện kho lưu trữ bằng phương thức truy vấn và truy vấn được xác định theo cách thủ công:



-  Để tránh nêu tên thực thể thực trong chuỗi truy vấn của chú thích @Query, bạn có thể sử dụng biến # {# entityName}.

- Một trường hợp sử dụng khác cho biểu thức # {# EntityName} trong chuỗi truy vấn là nếu bạn muốn xác định giao diện kho lưu trữ chung với các giao diện kho lưu trữ chuyên dụng cho loại miền cụ thể. Để không lặp lại định nghĩa về các phương thức truy vấn tùy chỉnh trên các giao diện cụ thể, bạn có thể sử dụng biểu thức tên thực thể trong chuỗi truy vấn của chú thích @query trong giao diện kho lưu trữ chung, như được hiển thị trong ví dụ sau:



- Các biểu thức trò chơi để thao tác các đối số cũng có thể được sử dụng để thao tác các đối số phương thức. Trong các biểu thức SPEL này, tên thực thể không khả dụng, nhưng các đối số là. Chúng có thể được truy cập theo tên hoặc chỉ mục như được chứng minh trong ví dụ sau.



- Đối với các điều kiện tương tự, người ta thường muốn thêm% vào đầu hoặc cuối của tham số có giá trị Chuỗi. Điều này có thể được thực hiện bằng cách thêm hoặc thêm vào trước một điểm đánh dấu tham số liên kết hoặc một biểu thức SpEL với%. Một lần nữa ví dụ sau đây chứng minh điều này.



- Khi sử dụng các điều kiện tương tự với các giá trị đến từ nguồn không bảo mật, các giá trị nên được vệ sinh để chúng không thể chứa bất kỳ ký tự đại diện nào và do đó cho phép kẻ tấn công chọn nhiều dữ liệu hơn so với chúng sẽ có thể. Với mục đích này, phương thức thoát (chuỗi) được cung cấp trong bối cảnh SPEL. Nó có tiền tố tất cả các phiên bản của _ và% trong đối số đầu tiên với ký tự đơn lẻ từ đối số thứ hai. Kết hợp với mệnh đề thoát của biểu thức giống như có sẵn trong JPQL và SQL tiêu chuẩn, điều này cho phép dễ dàng làm sạch các tham số liên kết.



6.3.8: Sửa đổi truy vấn

- Tất cả các phần trước mô tả cách khai báo các truy vấn để truy cập một thực thể hoặc bộ sưu tập các thực thể nhất định. Bạn có thể thêm hành vi sửa đổi tùy chỉnh bằng cách sử dụng các phương thức tùy chỉnh được mô tả trong "triển khai tùy chỉnh cho kho dữ liệu mùa xuân". Vì cách tiếp cận này là khả thi cho chức năng tùy chỉnh toàn diện, bạn có thể sửa đổi các truy vấn chỉ cần ràng buộc tham số bằng cách chú thích phương thức truy vấn với @modifying, như thể hiện trong ví dụ sau:



- Xóa truy vấn có nguồn gốc

- Spring Data JPA cũng hỗ trợ các truy vấn xóa bắt nguồn cho phép bạn tránh phải khai báo truy vấn JPQL một cách rõ ràng, như được hiển thị trong ví dụ sau:



6.3.9: Áp dụng gợi ý truy vấn

- Để áp dụng gợi ý truy vấn JPA cho các truy vấn được khai báo trong giao diện kho lưu trữ của bạn, bạn có thể sử dụng chú thích @QueryHint. Phải mất một loạt các chú thích JPA @QueryHint cộng với cờ Boolean để có khả năng vô hiệu hóa các gợi ý được áp dụng cho truy vấn đếm bổ sung được kích hoạt khi áp dụng phân trang, như trong ví dụ sau:



6.3.10: Cấu hình Fetch- và LoadGraphs

- Thông số kỹ thuật JPA 2.1 đã giới thiệu hỗ trợ để chỉ định Fetch- và Loadgraphs mà chúng tôi cũng hỗ trợ chú thích @entityGraph, cho phép bạn tham khảo định nghĩa @NamedentityGraph. Bạn có thể sử dụng chú thích đó trên một thực thể để định cấu hình gói tìm nạp của truy vấn kết quả. Loại (tìm nạp hoặc tải) của tìm nạp có thể được cấu hình bằng cách sử dụng thuộc tính loại trên chú thích @entityGraph. Xem JPA 2.1 Spec 3.7.4 để tham khảo thêm.



- Ví dụ sau cho thấy cách tham chiếu một biểu đồ thực thể được đặt tên trên phương pháp truy vấn kho lưu trữ:



- Cũng có thể xác định biểu đồ thực thể ad hoc bằng cách sử dụng @entityGraph. Các thuộc tính được cung cấp được dịch sang chế độ thực thể mà không cần thêm @namedentityGraph rõ ràng vào các loại tên miền của bạn, như trong ví dụ sau:



6.3.11: Các phép chiếu

- Các phương thức truy vấn dữ liệu Spring thường trả về một hoặc nhiều phiên bản của root tổng hợp được quản lý bởi kho lưu trữ. Tuy nhiên, đôi khi có thể mong muốn tạo các hình chiếu dựa trên các thuộc tính nhất định của các loại đó. Dữ liệu lò xo cho phép mô hình hóa các loại trả về chuyên dụng, để lấy nhiều cách chọn lọc các chế độ xem một phần của tổng hợp được quản lý.

- Hãy tưởng tượng một kho lưu trữ và kiểu gốc tổng hợp chẳng hạn như ví dụ sau:



- Phép chiếu dựa trên interface



- Kho lưu trữ sử dụng phép chiếu dựa trên giao diện với phương thức truy vấn



- Phép chiếu có thể được sử dụng một cách đệ quy. Nếu bạn cũng muốn bao gồm một số thông tin Địa chỉ, hãy tạo giao diện chiếu cho thông tin đó và trả lại giao diện đó từ khai báo getAddress (), như được hiển thị trong ví dụ sau:



- Các dự báo đã đóng

- Một giao diện chiếu mà các phương thức của bộ truy cập đều phù hợp với các thuộc tính của tổng hợp mục tiêu được coi là một phép chiếu đóng. Ví dụ sau (mà chúng ta cũng đã sử dụng trước đó trong chương này) là một phép chiếu khép kín:



- Mở các phép chiếu

- Phương thức truy cập trong giao diện chiếu cũng có thể được sử dụng để tính toán các giá trị mới bằng cách sử dụng chú thích @Value, như được hiển thị trong ví dụ sau:



- Các biểu thức được sử dụng trong @Value không được quá phức tạp - bạn muốn tránh lập trình trong các biến Chuỗi. Đối với các biểu thức rất đơn giản, một tùy chọn có thể là sử dụng các phương thức mặc định (được giới thiệu trong Java 8), như được hiển thị trong ví dụ sau:



- Cách tiếp cận này yêu cầu bạn có thể triển khai logic hoàn toàn dựa trên các phương thức truy cập khác được hiển thị trên giao diện chiếu. Tùy chọn thứ hai, linh hoạt hơn, tùy chọn là triển khai logic tùy chỉnh trong một hạt lò xo và sau đó gọi đó là từ biểu thức SPEL, như thể hiện trong ví dụ sau:



- Phép chiếu động

- Cho đến nay, chúng tôi đã sử dụng loại chiếu là loại trả về hoặc loại phần tử của bộ sưu tập. Tuy nhiên, bạn có thể muốn chọn loại sẽ được sử dụng tại thời điểm gọi (giúp nó động). Để áp dụng các dự báo động, hãy sử dụng một phương pháp truy vấn như bảng hiển thị trong ví dụ sau:



- Bằng cách này, phương pháp có thể được sử dụng để thu được các tổng thể nguyên trạng hoặc với phép chiếu được áp dụng, như thể hiện trong ví dụ sau:






6.4. Thủ tục lưu trữ

Đặc tả JPA 2.1 đã giới thiệu hỗ trợ gọi các thủ tục được lưu trữ bằng cách sử dụng API truy vấn tiêu chí JPA. Chúng tôi đã giới thiệu chú thích @Procedure để khai báo siêu dữ liệu thủ tục được lưu trữ trên phương thức kho lưu trữ.

 

Các ví dụ để làm theo sử dụng quy trình được lưu trữ sau:

Ví dụ 91. Định nghĩa thủ tục plus1inout trong HSQL DB.


Siêu dữ liệu cho các thủ tục được lưu trữ có thể được định cấu hình bằng cách sử dụng chú thích NamedStoredProcedureQuery trên một loại thực thể.

 

Ví dụ 92. Định nghĩa siêu dữ liệu StoredProcedure trên một thực thể.


Lưu ý rằng @NamedStoredProcedureQuery có hai tên khác nhau cho thủ tục được lưu trữ. tên là tên mà JPA sử dụng. procedureName là tên mà thủ tục được lưu trữ có trong cơ sở dữ liệu.

 

Bạn có thể tham chiếu các thủ tục được lưu trữ từ một phương pháp kho lưu trữ theo nhiều cách. Thủ tục được lưu trữ sẽ được gọi có thể được định nghĩa trực tiếp bằng cách sử dụng thuộc tính value hoặc procedureName của chú thích @Procedure. Điều này đề cập trực tiếp đến thủ tục được lưu trữ trong cơ sở dữ liệu và bỏ qua bất kỳ cấu hình nào qua @NamedStoredProcedureQuery.

 

Ngoài ra, bạn có thể chỉ định thuộc tính @ NamedStoredProcedureQuery.name làm thuộc tính @ Procedure.name. Nếu cả giá trị, tên thủ tục và tên đều không được định cấu hình, tên của phương thức kho lưu trữ được sử dụng làm thuộc tính tên.

 

Ví dụ sau cho thấy cách tham chiếu một thủ tục được ánh xạ rõ ràng:

Ví dụ 93. Tham chiếu thủ tục được ánh xạ rõ ràng với tên "plus1inout" trong cơ sở dữ liệu.


Ví dụ sau tương đương với ví dụ trước nhưng sử dụng bí danh procedureName:

 

Ví dụ 94. Tham chiếu đến thủ tục được ánh xạ ngầm với tên "plus1inout" trong cơ sở dữ liệu thông qua bí danh procedureName.


 

Phần sau lại tương đương với hai phần trước nhưng sử dụng tên phương thức thay vì thuộc tính chú thích giải thích.

Ví dụ 95. Tham chiếu thủ tục được lưu trữ được ánh xạ ngầm có tên "User.plus1" trong EntityManager bằng cách sử dụng tên phương thức.


Ví dụ sau đây cho thấy cách tham chiếu một thủ tục được lưu trữ bằng cách tham chiếu thuộc tính @ NamedStoredProcedureQuery.name.

 

Ví dụ 96. Tham chiếu thủ tục được lưu trữ có tên được ánh xạ rõ ràng "User.plus1IO" trong EntityManager.


 

Nếu thủ tục được lưu trữ đang được gọi có một tham số duy nhất thì tham số đó có thể được trả về dưới dạng giá trị trả về của phương thức. Nếu có nhiều tham số được chỉ định trong chú thích @NamedStoredProcedureQuery, chúng có thể được trả về dưới dạng Bản đồ với khóa là tên tham số được cung cấp trong chú thích @NamedStoredProcedureQuery.

6.5. Thông số kỹ thuật

JPA 2 giới thiệu một API tiêu chí mà bạn có thể sử dụng để tạo các truy vấn theo chương trình. Bằng cách viết một tiêu chí, bạn xác định mệnh đề where của một truy vấn cho một lớp miền. Lùi lại một bước nữa, các tiêu chí này có thể được coi là một vị từ đối với thực thể được mô tả bởi các ràng buộc API tiêu chí JPA.

 

Spring Data JPA lấy khái niệm về một đặc tả từ cuốn sách của Eric Evans, “Thiết kế theo hướng miền”, theo cùng một ngữ nghĩa và cung cấp một API để xác định các thông số kỹ thuật đó với API tiêu chí JPA. Để hỗ trợ các thông số kỹ thuật, bạn có thể mở rộng giao diện kho lưu trữ của mình với giao diện JpaSpecificationExecutor, như sau:


Giao din b sung có các phương thc cho phép bn chy các thông s k thut theo nhiu cách khác nhau. Ví d: phương thc findAll tr v tt c các thc th phù hp vi đặc t, như được hin th trong ví d sau:


 

Giao din Đặc đim k thut được định nghĩa như sau:


 

Các thông s k thut có th d dàng được s dng để xây dng mt tp hp các v t có th m rng trên đầu mt thc th mà sau đó có th được kết hp và s dng vi JpaRepository mà không cn khai báo mt truy vn (phương thc) cho mi kết hp cn thiết, như được hin th trong ví d sau:

Ví d 97. Thông s k thut cho mt Khách hang




 

Loi Customer_ là loi siêu mô hình được to bng cách s dng trình to siêu mô hình JPA (xem tài liu v trin khai Hibernate để làm ví d). Vì vy, biu thc, Customer_.createAt, gi s Khách hàng có thuc tính createAt ca loi Ngày. Bên cnh đó, chúng tôi đã th hin mt s tiêu chí v mc độ tru tượng hóa yêu cu kinh doanh và to ra các Thông s k thut có th thc thi. Vì vy, khách hàng có th s dng mt Đặc đim k thut như sau:

 

Ví d 98. S dng mt Đặc t đơn gin


 

Ti sao không to mt truy vn cho loi truy cp d liu này? S dng mt Đặc t đơn l không thu được nhiu li ích so vi khai báo truy vn đơn gin. Sc mnh ca các thông s k thut thc s ta sáng khi bn kết hp chúng để to các đối tượng Thông s k thut mi. Bn có th đạt được điu này thông qua các phương pháp mc định ca Đặc t mà chúng tôi cung cp để xây dng các biu thc tương t như sau:

 

Ví d 99. Thông s k thut kết hp



 

6.6. Truy vn bng ví d

6.6.1. Gii thiu

Chương này gii thiu v Truy vn bng Ví d và gii thích cách s dng nó.

 

Truy vn bng ví d (QBE) là mt k thut truy vn thân thin vi người dùng vi giao din đơn gin. Nó cho phép to truy vn động và không yêu cu bn viết các truy vn có cha tên trường. Trên thc tế, Truy vn theo Ví d hoàn toàn không yêu cu bn viết các truy vn bng cách s dng các ngôn ng truy vn dành riêng cho ca hàng.

 

6.6.2. S dng

·        API Truy vn theo Ví d bao gm ba phn:

 

·        Probe: Ví d thc tế v mt đối tượng min vi các trường được đin.

 

·        ExampleMatcher: ExampleMatcher cung cp thông tin chi tiết v cách đối sánh các trường c th. Nó có th được s dng li trên nhiu Ví d.

 

·        Ví d: Mt Ví d bao gm đầu dò và Ví d v Đối sánh. Nó được s dng để to truy vn.

 

·        Truy vn theo Ví d rt phù hp cho mt s trường hp s dng:

 

·        Truy vn kho d liu ca bn vi mt tp hp các ràng buc tĩnh hoc động.

 

·        Thường xuyên tái cu trúc các đối tượng min mà không phi lo lng v vic phá v các truy vn hin có.

 

·        Làm vic độc lp vi API lưu tr d liu cơ bn.

·        Truy vn theo Ví d cũng có mt s hn chế:

 

·        Không h tr các ràng buc thuc tính lng nhau hoc nhóm, chng hn như firstname =? 0 hoc (firstname =? 1 và lastname =? 2).

 

·        Ch h tr đối sánh bt đầu / cha / kết thúc / regex cho các chui và đối sánh chính xác cho các loi thuc tính khác.

 

·        Trước khi bt đầu vi Truy vn bng ví d, bn cn có mt đối tượng min. Để bt đầu, hãy to giao din cho kho lưu tr ca bn, như được hin th trong ví d sau:

 

Ví d 100. Đối tượng Người mu



 

Ví d trước cho thy mt đối tượng min đơn gin. Bn có th s dng nó để to mt Ví d. Theo mc định, các trường có giá tr null s b b qua và các chui được khp bng cách s dng các giá tr mc định c th ca ca hàng.



Các ví d có th được to bng cách s dng phương thc ca nhà máy hoc bng cách s dng ExampleMatcher. Ví d là bt biến. Danh sách sau đây cho thy mt ví d đơn gin:

Ví d 101. Ví d đơn gin



 

Bn có th chy các truy vn mu bng cách s dng kho lưu tr. Để làm như vy, hãy để giao din kho lưu tr ca bn m rng QueryByExampleExecutor <T>. Danh sách sau đây hin th mt đon trích t giao din QueryByExampleExecutor:

 

Ví d 102. QueryByExampleExecutor



 

6.6.3. Đối sánh ví d

Ví d không gii hn cài đặt mc định. Bn có th ch định các giá tr mc định ca riêng mình cho đối sánh chui, x lý null và cài đặt thuc tính c th bng cách s dng ExampleMatcher, như được hin th trong ví d sau:

 

Ví d 103. Đối sánh ví d vi đối sánh tùy chnh



 

Theo mc định, ExampleMatcher mong đợi tt c các giá tr được đặt trên đầu dò phi khp. Nếu bn mun nhn kết qu khp vi bt k v t nào được xác định ngm, hãy s dng ExampleMatcher.matchingAny ().

 

Bn có th ch định hành vi cho các thuc tính riêng l (chng hn như "firstname" và "lastname" hoc đối vi các thuc tính lng nhau, "address.city"). Bn có th điu chnh nó vi các tùy chn phù hp và phân bit ch hoa ch thường, như được hin th trong ví d sau:

 

Ví d 104. Định cu hình các tùy chn so khp



Mt cách khác để định cu hình các tùy chn so khp là s dng lambdas (được gii thiu trong Java 8). Cách tiếp cn này to ra mt lnh gi li yêu cu người trin khai sa đổi trình kết hp. Bn không cn tr li trình so khp, vì các tùy chn cu hình được gi trong phiên bn so khp. Ví d sau cho thy mt trình so khp s dng lambdas:

 

Ví d 105. Định cu hình các tùy chn so khp vi lambdas



 

Các truy vn được to bi Ví d s dng chế độ xem cu hình đã hp nht. Cài đặt đối sánh mc định có th được đặt cp ExampleMatcher, trong khi cài đặt riêng l có th được áp dng cho các đường dn thuc tính c th. Cài đặt được đặt trên ExampleMatcher được kế tha bi cài đặt đường dn thuc tính tr khi chúng được xác định rõ ràng. Cài đặt trên bn vá thuc tính có mc độ ưu tiên cao hơn cài đặt mc định. Bng sau đây mô t phm vi ca các cài đặt ExampleMatcher khác nhau:



 

6.6.4. Chy mt ví d

Trong Spring Data JPA, bn có th s dng Truy vn theo Ví d vi Kho lưu tr, như được hin th trong ví d sau:

 

Ví d 106. Truy vn theo Ví d s dng Kho lưu tr



 

B ch định thuc tính chp nhn tên thuc tính (chng hn như h và tên). Bn có th điu hướng bng cách xâu chui các thuc tính vi nhau bng các du chm (address.city). Bn cũng có th điu chnh nó bng các tùy chn phù hp và phân bit ch hoa ch thường.

 

Bng sau đây cho thy các tùy chn StringMatcher khác nhau mà bn có th s dng và kết qu ca vic s dng chúng trên mt trường có tên firstname:



 

6,7. Giao dch

Theo mc định, các phương thc CRUD trên các phiên bn kho lưu tr được kế tha t SimpleJpaRepository là giao dch. Đối vi các hot động đọc, c cu hình giao dch readOnly được đặt thành true. Tt c nhng th khác được định cu hình bng @Transactional thun túy để cu hình giao dch mc định được áp dng. Các phương thc kho lưu tr được h tr bi các phân đon kho lưu tr giao dch kế tha các thuc tính giao dch t phương thc phân mnh thc tế.

 

Nếu bn cn chnh sa cu hình giao dch cho mt trong các phương thc được khai báo trong kho lưu tr, hãy khai báo li phương thc đó trong giao din kho lưu tr ca bn, như sau:

 

Ví d 107. Cu hình giao dch tùy chnh cho CRUD



 

Mt cách khác để thay đổi hành vi giao dch là s dng mt mt tin hoc trin khai dch v (thường) bao gm nhiu hơn mt kho lưu tr. Mc đích ca nó là xác định ranh gii giao dch cho các hot động không phi CRUD. Ví d sau đây cho thy cách s dng mt mt tin như vy cho nhiu kho lưu tr:

Ví d 108. S dng mt mt tin để xác định các giao dch cho nhiu lnh gi kho lưu tr



Ví d này khiến lnh gi addRoleToAllUsers (…) chy bên trong mt giao dch (tham gia vào mt giao dch hin có hoc to mt giao dch mi nếu chưa có giao dch nào đang chy). Cu hình giao dch ti các kho lưu tr sau đó b b qua, vì cu hình giao dch bên ngoài xác định cu hình thc s được s dng. Lưu ý rng bn phi kích hot <tx: annotation-driven /> hoc s dng @EnableTransactionManagement mt cách rõ ràng để cu hình mt tin hot động da trên chú thích. Ví d này gi s bn s dng tính năng quét thành phn.

 

Lưu ý rng lnh gi lưu không hoàn toàn cn thiết theo quan đim ca JPA, nhưng vn nên đó để duy trì tính tru tượng ca kho lưu tr được cung cp bi Spring Data.

 

6.7.1. Các phương pháp truy vn giao dch

Để cho phép các phương thc truy vn ca bn được giao dch, hãy s dng @Transactional ti giao din kho lưu tr mà bn xác định, như được hin th trong ví d sau:

 

Ví d 109. S dng @Transactional ti các phương thc truy vn



 

6,8. Khóa

Để ch định chế độ khóa được s dng, bn có th s dng chú thích @Lock trên các phương thc truy vn, như được hin th trong ví d sau:

 

Ví d 110. Định nghĩa siêu d liu khóa trên các phương thc truy vn



Khai báo phương pháp này làm cho truy vn được kích hot được trang b LockModeType of READ. Bn cũng có th xác định khóa cho các phương thc CRUD bng cách khai báo li chúng trong giao din kho lưu tr ca mình và thêm chú thích @Lock, như được hin th trong ví d sau:

 

Ví d 111. Định nghĩa siêu d liu khóa trên các phương thc CRUD



 

6,9. Kim toán

6.9.1. Khái nim cơ bn

Spring Data cung cp h tr tinh vi để theo dõi minh bch ai đã to hoc thay đổi mt thc th và khi nào thay đổi xy ra. Để được hưởng li t chc năng đó, bn phi trang b cho các lp thc th ca mình siêu d liu kim tra có th được xác định bng cách s dng chú thích hoc bng cách trin khai giao din. Ngoài ra, kim tra phi được kích hot thông qua cu hình Chú thích hoc cu hình XML để đăng ký các thành phn cơ s h tng được yêu cu. Vui lòng tham kho phn dành riêng cho ca hàng để biết các mu cu hình.



Siêu d liu kim tra da trên chú thích

Chúng tôi cung cp @CreateBy và @LastModifiedBy để nm bt người dùng đã to hoc sa đổi thc th cũng như @CreateDate và @LastModifiedDate để nm bt thi đim thay đổi xy ra.

 

Ví d 112. Đơn v được kim toán



 

Như bn có th thy, các chú thích có th được áp dng mt cách chn lc, tùy thuc vào thông tin bn mun nm bt. Các chú thích ghi li thi đim các thay đổi được thc hin có th được s dng trên các thuc tính ca loi Joda-Time, DateTime, Ngày và Lch Java kế tha, các loi ngày và gi JDK8 và Long hoc Long.

 

Siêu d liu kim tra không nht thiết phi tn ti trong thc th cp cơ s nhưng có th được thêm vào mt thc th được nhúng (tùy thuc vào ca hàng thc tế đang được s dng), như được hin th trong phn bên dưới.

 

Ví d 113. Siêu d liu kim tra trong thc th được nhúng



 

Siêu d liu kim toán da trên giao din

Trong trường hp bn không mun s dng chú thích để xác định siêu d liu kim tra, bn có th để lp min ca mình trin khai giao din Auditable. Nó cho thy các phương pháp setter cho tt c các thuc tính kim toán.

 

Ngoài ra còn có mt lp cơ s tin li, AbstractAuditable, mà bn có th m rng để tránh phi trin khai các phương thc giao din theo cách th công. Làm như vy s tăng s kết hp các lp min ca bn vi D liu mùa xuân, đây có thđiu bn mun tránh. Thông thường, cách xác định siêu d liu kim tra da trên chú thích được ưu tiên hơn vì nó ít xâm ln hơn và linh hot hơn.

 

AuditorAware

Trong trường hp bn s dng @CreateBy hoc @LastModifiedBy, cơ s h tng kim toán bng cách nào đó cn phi biết v nguyên tc chính hin ti. Để làm như vy, chúng tôi cung cp giao din AuditorAware <T> SPI mà bn phi trin khai để cho cơ s h tng biết người dùng hoc h thng hin ti tương tác vi ng dng là ai. Kiu chung T xác định loi thuc tính được chú thích bng @CreateBy hoc @LastModifiedBy phi là.

 

Ví d sau cho thy cách trin khai giao din s dng đối tượng Xác thc ca Spring Security:

 

Ví d 114. Trin khai AuditorAware da trên Spring Security



 

Vic trin khai truy cp đối tượng Xác thc do Spring Security cung cp và tra cu phiên bn UserDetails tùy chnh mà bn đã to trong quá trình trin khai UserDetailsService ca mình. đây, chúng tôi gi định rng bn đang tiết l người dùng min thông qua trin khai UserDetails nhưng da trên Xác thc được tìm thy, bn cũng có th tra cu nó t bt k đâu.

 

ReactiveAuditorAware

Khi s dng cơ s h tng phn ng, bn có th mun s dng thông tin theo ng cnh để cung cp thông tin @CreateBy hoc @LastModifiedBy. Chúng tôi cung cp giao din ReactiveAuditorAware <T> SPI mà bn phi trin khai để cho cơ s h tng biết người dùng hoc h thng hin ti tương tác vi ng dng là ai. Kiu chung T xác định loi thuc tính được chú thích bng @CreateBy hoc @LastModifiedBy phi là.

 

Ví d sau cho thy cách trin khai giao din s dng đối tượng Xác thc ca Spring Security phn ng:

 

Ví d 115. Trin khai ReactiveAuditorAware da trên Spring Security



 

Vic trin khai truy cp vào xác thc đối tượng do Spring Security cung cp và tra cu UserDetails phiên bn tùy chnh mà bn đã to ra trong quá trình trin khai UserDetailsService ca mình. đây, chúng tôi gi định rng bn đang tiết l người dùng min thông qua phát trin UserDetails nhưng da trên Xác thc được tìm thy, bn cũng có th tìm kiếm nó t bt k đâu. : leveloffset: -1

 

6.9.2. JPA kim toán

Chung thanh toán cu hình

Spring Data JPA cung cp mt trình thc thi có th được s dng để kích hot công vic kim tra thông tin thp phân. Trước tiên, bn phi đăng ký AuditingEntityListener để được s dng cho tt c các thc thi trong liên tc ng cnh bên trong tp orm.xml ca bn, như được hin th trong ví d sau:

 

Ví d 116. Cu hình kim tra orm.xml



 

Bn cũng có th bt AuditingEntityListener trên cơ s mi t chc bng cách s dng chú thích @EntityListener, như sau:



 

Vi orm.xml được sa đổi phù hp và spring-domains.jar trên classpath, vic kích hot chc năng kim tra là vn đề ca vic thêm phn t không gian tên kim tra Spring Data JPA vào cu hình ca bn, như sau:

 

Ví d 117. Kích hot kim tra bng cách s dng cu hình XML



 

T Spring Data JPA 1.5, bn có th bt kim tra bng cách chú thích mt cu hình lp vi chú thích @EnableJpaAuditing. Bn vn phi sa đổi file orm.xml và có spring-domains.jar trên classpath. Ví d sau cho cách s dng chú thích @EnableJpaAuditing:

 

Ví d 118. Kích hot kim tra bng cu hình Java



Nếu bn để l mt bean loi AuditorAware vi ApplicationContext, cơ s h tng kim tra s t động chn nó và s dng nó để xác định người dùng hin ti được đặt trên các loi min. Nếu bn có nhiu trin khai được đăng ký trong ApplicationContext, bn có th chn mt trin khai s được s dng bng cách thiết lp rõ ràng thuc tính auditorAwareRef ca @EnableJpaAuditing.

 

6.10. Các cân nhc khác

6.10.1. S dng JpaContext trong Trin khai Tùy chnh

Khi làm vic vi nhiu cá th EntityManager và trin khai kho lưu tr tùy chnh, bn cn chuyn EntityManager chính xác vào lp trin khai kho lưu tr. Bn có th làm như vy bng cách đặt tên rõ ràng cho EntityManager trong chú thích @PersistenceContext hoc, nếu EntityManager là @Autowosystem, bng cách s dng @Qualifier.

 

K t Spring Data JPA 1.9, Spring Data JPA bao gm mt lp gi là JpaContext cho phép bn ly EntityManager theo lp min được qun lý, gi s rng nó ch được qun lý bi mt trong các phiên bn EntityManager trong ng dng. Ví d sau đây cho thy cách s dng JpaContext trong mt kho lưu tr tùy chnh:

 

Ví d 119. S dng JpaContext trong trin khai kho lưu tr tùy chnh



 

Ưu đim ca cách tiếp cn này là, nếu loi min được gán cho mt đơn v lâu dài khác, kho lưu tr không cn phi được chm vào để thay đổi tham chiếu đến đơn v lâu dài.

 

6.10.2. Hp nht các đơn v bn vng

Spring h tr có nhiu đơn v độ bn. Tuy nhiên, đôi khi, bn có th mun mô-đun hóa ng dng ca mình nhưng vn đảm bo rng tt c các mô-đun này chy bên trong mt đơn v bn b duy nht. Để kích hot hành vi đó, Spring Data JPA cung cp trin khai PersistenceUnitManager t động hp nht các đơn v bn vng da trên tên ca chúng, như được hin th trong ví d sau:

 

Ví d 120. S dng MergingPersistenceUnitmanager



 

Quét Classpath cho các lp @Entity và tp ánh x JPA

Thiết lp JPA thun túy yêu cu tt c các lp thc th được ánh x chú thích phi được lit kê trong orm.xml. Điu tương t cũng áp dng cho các tp ánh x XML. Spring Data JPA cung cp mt ClasspathScanningPersistenceUnitPostProcessor để cu hình gói cơ s và tùy chn ly mu tên tp ánh x. Sau đó, nó s quét gói đã cho để tìm các lp được chú thích bng @Entity hoc @MappedSuperclass, ti các tp cu hình phù hp vi mu tên tp và đưa chúng vào cu hình JPA. B x lý hu k phi được định cu hình như sau:

 

Ví d 121. S dng ClasspathScanningPersistenceUnitPostProcessor



 

6.10.3. Tích hp CDI

Các phiên bn ca giao din kho lưu tr thường được to bi mt vùng cha, trong đó Spring là la chn t nhiên nht khi làm vic vi Spring Data. Spring cung cp h tr tinh vi để to các cá th bean, như được ghi li trong To các Phiên bn Kho lưu tr. K t phiên bn 1.1.0, Spring Data JPA đi kèm vi phn m rng CDI tùy chnh cho phép s dng tính tru tượng ca kho lưu tr trong môi trường CDI. Phn m rng là mt phn ca JAR. Để kích hot nó, hãy bao gm Spring Data JPA JAR trên classpath ca bn.

 

Bây gi bn có th thiết lp cơ s h tng bng cách trin khai CDI Producer cho EntityManagerFactory và EntityManager, như được minh ha trong ví d sau:



 

Thiết lp cn thiết có th khác nhau tùy thuc vào môi trường JavaEE. Bn có th không cn làm gì khác hơn là khai báo li EntityManager dưới dng bean CDI, như sau:



 

Trong ví d trước, vùng cha phi có kh năng t to JPA EntityManagers. Tt c nhng gì cu hình làm là tái xut JPA EntityManager dưới dng mt bean CDI.

 

Phn m rng Spring Data JPA CDI chn tt c các phiên bn EntityManager có sn dưới dng các bean CDI và to mt proxy cho kho lưu tr Spring Data bt c khi nào vùng cha yêu cu mt bean thuc loi kho lưu tr. Do đó, vic có được mt phiên bn ca kho lưu tr D liu mùa xuân là vn đề khai báo thuc tính @Injected, như th hin trong ví d sau:



 



- Tham chiếu không gian tên:

Ph<repositories />t kích hot thiết lp cơ s h tng kho lưu tr D liu mùa   xuân. Thuc tính quan trng nht là base-package, xác định gói để quét các giao din ca kho lưu tr D liu Mùa xuân. Xem “ Cu hình XML ”. Bng sau đây mô t các thuc tính c<repositories />phn t:


 

-Tham chiếu không gian tên của nhà phổ biến:

Phần tử <phổ biến /> Tham chiếu không gian tên của nhà phổ biến

Ph<populator />t cho phép đưa vào kho lưu tr d liu thông qua cơ s h tng kho lưu tr D liu Mùa xuân.


 

- Từ khóa truy vấn kho lưu trữ:

Từ khóa chủ đề của phương pháp truy vấn được hỗ trợ

Bng sau lit kê các t khóa ch đề thường được h tr bi cơ chế dn xut truy vn ca kho lưu tr D liu Mùa xuân để din đạt v t. Tham kho tài liu dành riêng cho ca hàng để biết danh sách chính xác các t khóa được h tr, bi vì mt s t khóa được lit kê đây có th không được h tr trong mt ca hàng c th.


 

Các từ khóa và công cụ sửa đổi vị ngữ của phương pháp truy vấn được hỗ trợ

Bng sau lit kê các t khóa v t thường được cơ chế dn xut truy vn ca kho lưu tr D liu Mùa xuân h tr. Tuy nhiên, hãy tham kho tài liu dành riêng cho ca hàng để biết danh sách chính xác các t khóa được h tr, vì mt s t khóa được lit kê đây có th không được h tr trong mt ca hàng c th.




Ngoài các v t b lc, danh sách các b ng sau được h tr:


Các kiểu trả về truy vấn kho lưu trữ

 

Các từ khóa và công cụ sửa đổi vị ngữ của phương pháp truy vấn được hỗ trợ

Bảng sau liệt kê các từ khóa vị từ thường được cơ chế dẫn xuất truy vấn của kho lưu trữ Dữ liệu Mùa xuân hỗ trợ. Tuy nhiên, hãy tham khảo tài liệu dành riêng cho cửa hàng để biết danh sách chính xác các từ khóa được hỗ trợ, vì một số từ khóa được liệt kê ở đây có thể không được hỗ trợ trong một cửa hàng cụ thể.




Các câu hỏi thường gặp

Chung

Tôi muốn lấy thông tin ghi nhật ký chi tiết hơn về những phương thức được gọi là bên trong JpaRepositorychẳng hạn. Làm thế nào tôi có thể đạt được chúng?

Bạn có thể sử dụng CustomizableTraceInterceptorSpring cung cấp, như thể hiện trong ví dụ sau:

 


 

Cơ sở hạ tầng

Hiện tại tôi đã triển khai một lớp kho lưu trữ dựa trên HibernateDaoSupport. Tôi tạo một SessionFactorybằng cách sử dụng Spring's AnnotationSessionFactoryBean. Làm cách nào để làm cho kho lưu trữ Dữ liệu mùa xuân hoạt động trong môi trường này?

Bạn phải thay thế AnnotationSessionFactoryBeanbằng HibernateJpaSessionFactoryBean, như sau:

Ví d 122. Tra SessionFactoryt aHibernateEntityManagerFactory


Kiểm toán

Tôi muốn sử dụng khả năng kiểm tra Spring Data JPA nhưng cơ sở dữ liệu của tôi đã được định cấu hình để đặt ngày sửa đổi và tạo trên các thực thể. Làm cách nào để ngăn Dữ liệu mùa xuân đặt ngày theo chương trình?

Đặt set-datesthuộc tính của auditingphần tử không gian tên thành false.

Phụ lục F: Bảng chú giải thuật ngữ

AOP

Lập trình định hướng Aspect

Commons DBCP

Commons DataBase Connection Pools - một thư viện từ nền tảng Apache cung cấp triển khai gộp giao diện DataSource.

HUNG ÁC

Tạo, Đọc, Cập nhật, Xóa - Các thao tác bền bỉ cơ bản.

DAO

Đối tượng truy cập dữ liệu - Mẫu để tách logic tồn tại khỏi đối tượng được duy trì

Tiêm phụ thuộc

Mẫu để chuyển sự phụ thuộc của một thành phần cho thành phần từ bên ngoài, giải phóng thành phần để tra cứu chính thành phần đó. Để biết thêm thông tin, hãy xemhttps://en.wikipedia.org/wiki/Dependency_Injection.

EclipseLink

Trình ánh xạ quan hệ đối tượng triển khai JPA - https://www.eclipse.org/eclipselink/

Ngủ đông

Trình ánh xạ quan hệ đối tượng triển khai JPA - https://hibernate.org/

JPA

Java Persistence API

Mùa xuân

Khung ứng dụng Java - https://projects.spring.io/spring-framework

 

Không có nhận xét nào:

Đăng nhận xét