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ề.
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 repositories
phầ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:
<?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.repositories
và tất cả các gói con của nó để tìm các giao diện mở rộng Repository
hoặ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 UserRepository
sẽ được đăng ký theo userRepository
. Tê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-package
thuộ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 Repository
giao 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:
<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 SomeRepository
việ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}Repositories
chú 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:
@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ể RepositoryFactory
mà bạn có thể sử dụng, như sau:
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:
interface CustomizedUserRepository {
void someCustomMethod(User user);
}
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:
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:
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
:
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ó:
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:
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-postfix
thuộ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à Impl
. Ví 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:
<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 CustomizedUserRepository
trướ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
.
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 UserRepository
giao diện với @Component("specialCustom")
, tên bean cộng Impl
sau đó khớp với tên được xác định cho việc triển khai kho lưu trữ trong com.acme.impl.two
và 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:
<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:
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 EntityInformation cộ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 EntityManager hoặ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 repositoryBaseClass
thuộc tính của @Enable${store}Repositories
chú thích, như được hiển thị trong ví dụ sau:
@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:
<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à @DomainEvents
mà 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:
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 @DomainEvents có 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:
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 Predicate tồn tại hay không. |
Để sử dụng hỗ trợ Querydsl, hãy mở rộng QuerydslPredicateExecutor
trên giao diện kho lưu trữ của bạn, như ví dụ sau cho thấy:
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 @EnableSpringDataWebSupport
chú thích trong lớp cấu hình JavaConfig của bạn, như ví dụ sau cho thấy:
@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration {}
Các @EnableSpringDataWebSupport
chú 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ý SpringDataWebConfiguration
hoặc HateoasAwareSpringDataWebConfiguration
dưới dạng Spring bean, như ví dụ sau cho thấy (cho SpringDataWebConfiguration
):
<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:
A Sử dụng
DomainClassConverter
Lớ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.HandlerMethodArgumentResolver
triển khai để cho Spring MVC giải quyếtPageable
và cácSort
phiê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ư
Point
và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 DomainClassConverter
Lớp học
Các DomainClassConverter
lớ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:
@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 User
trự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 id
kiể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 PageableHandlerMethodArgumentResolver
cũng như một phiên bản của SortHandlerMethodArgumentResolver
. Việc đăng ký cho phép Pageable
và Sort
là đối số của phương thức bộ điều khiển hợp lệ, như ví dụ sau cho thấy:
@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 Pageable
thể 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:
| Trang bạn muốn truy xuất. 0 được lập chỉ mục và mặc định là 0. |
| Kích thước của trang bạn muốn truy xuất. Mặc định là 20. |
| Thuộc tính nên được sắp xếp theo định dạng |
Để tùy chỉnh hành vi này, hãy đăng ký một bean triển khai PageableHandlerMethodArgumentResolverCustomizer
giao diện hoặc SortHandlerMethodArgumentResolverCustomizer
giao 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ó MethodArgumentResolver
không đủ cho mục đích của bạn, hãy mở rộng một trong hai SpringDataWebConfiguration
hoặ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 @Enable
chú thích.
Nếu bạn cần nhiều Pageable
hoặc nhiều Sort
phiê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 @Qualifier
chú 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_page
, thing2_page
v.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 @PageableDefault
chú thích trên Pageable
tham 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 Page
phiên bản với Page
siê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 Page
thành a PagedResources
được thực hiện bằng cách triển khai ResourceAssembler
giao diện Spring HATEOAS , được gọi là PagedResourcesAssembler
. Ví 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ố:
@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
Page
trở thành nội dung củaPagedResources
cá thể.Đối
PagedResources
tượng đượcPageMetadata
đính kèm một thể hiện và nó được cung cấp thông tin từPage
bên dưới và bên dướiPageRequest
.Có
PagedResources
thể nhậnprev
vànext
liê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ủaPageableHandlerMethodArgumentResolver
để đả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 Person
phiê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 Pageable
yê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.Distance
và 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.ObjectMapper
khả 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 |
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:
@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 ParameterizedTypeReference
trên một trong các phương thức của RestTemplate
. Các khai báo phương thức trước đó sẽ cố gắng tìm firstname
bất kỳ đâu trong tài liệu đã cho. Việc lastname
tra 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 lastname
trước tiên nhưng cũng cố gắng lastname
lồng trong một user
tà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 @EnableSpringDataWebSupport
hoạ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 XmlBeamHttpMessageConverter
theo 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 Request
chuỗ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 @QuerydslPredicate
và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 root thuộc tính của QuerydslPredicate . |
Ví dụ sau đây cho thấy cách sử dụng @QuerydslPredicate
trong 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 Predicate cho User . |
Ràng buộc mặc định như sau:
Object
trên các thuộc tính đơn giản nhưeq
.Object
trên bộ sưu tập như thuộc tính nhưcontains
.Collection
trê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 bindings
thuộc tính của @QuerydslPredicate
hoặc bằng cách sử dụng Java 8 default methods
và thêm QuerydslBinderCustomizer
phươ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);
}
}
QuerydslPredicateExecutor cung 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 username tính là một contains ràng buộc đơn giản . | |
Xác định ràng buộc mặc định cho String các thuộc tính là contains đối sánh không phân biệt chữ hoa chữ thường . | |
Loại trừ password tài sản khỏi Predicate giải pháp. |
Bạn có thể đăng ký một QuerydslBinderCustomizerDefaults bean 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 DataSource
tậ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.json
với nội dung sau:
[ { "_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:
<?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.json
tệ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 _class
thuộ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-populator
phầ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:
<?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
- Phần này mô tả những
điều cơ bản về cấu 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 Persistable
: Nế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 diện bổ sung có các phương
thức
cho phép bạn chạy
các thông số kỹ thuật
theo nhiều
cách khác nhau. Ví dụ: phương thức
findAll trả về tất cả các
thực thể phù
hợp với đặc tả, như được hiển thị
trong ví dụ
sau:
Giao diện Đặc điểm kỹ thuật được định nghĩa như sau:
Các thông số kỹ thuật có thể dễ dàng được sử dụng để xây dựng một tập hợp các vị từ có thể mở rộng trên đầu một thực thể mà sau đó có thể được kết hợp và sử dụng với JpaRepository mà không cần khai báo một truy vấn (phương thức) cho mọi kết hợp cần thiết, như được hiển thị trong ví dụ sau:
Ví dụ 97. Thông số kỹ thuật
cho một
Khách hang
Loại
Customer_ là loại
siêu mô hình được tạo bằng cách sử dụng trình tạo siêu mô hình JPA
(xem tài liệu về triển khai Hibernate để làm ví dụ). Vì vậy, biểu thức,
Customer_.createAt, giả sử Khách hàng có thuộc tính createAt của loại Ngày. Bên cạnh đó, chúng
tôi đã thể hiện một số tiêu chí về mức độ trừu tượng hóa yêu cầu kinh doanh và tạo ra các Thông số kỹ thuật có thể thực thi. Vì vậy, khách hàng có thể sử dụng một Đặc điểm kỹ thuật như sau:
Ví dụ 98. Sử dụng một Đặc tả đơn giản
Tại
sao không tạo một truy vấn cho loại truy cập dữ liệu này? Sử dụng một Đặc tả đơn lẻ không thu được nhiều lợi ích so với khai báo truy vấn đơn giản. Sức mạnh của các thông số kỹ thuật thực sự tỏa sáng khi bạn kết hợp chúng để tạo các đối tượng Thông số kỹ thuật mới. Bạn có thể đạt được điều này thông qua các
phương pháp mặc định của Đặc tả mà chúng tôi cung cấp để xây dựng các biểu thức tương tự như sau:
Ví dụ 99. Thông số kỹ thuật kết hợp
6.6. Truy vấn bằng
ví dụ
6.6.1. Giới
thiệu
Chương này giới thiệu về Truy vấn bằng Ví dụ và giải thích cách sử dụng nó.
Truy vấn bằng ví dụ (QBE) là một kỹ thuật truy vấn thân thiện với người dùng với giao diện đơn giản. Nó cho phép tạo truy vấn động và không yêu cầu bạn viết các truy vấn có chứa tên trường. Trên thực tế, Truy vấn theo Ví dụ hoàn toàn không yêu
cầu bạn viết các truy vấn bằng cách sử dụng các ngôn ngữ truy vấn dành riêng cho cửa hàng.
6.6.2. Sử dụng
·
API Truy vấn theo Ví dụ bao gồm ba phần:
·
Probe: Ví dụ thực tế về một đối tượng miền với các trường được điền.
·
ExampleMatcher: ExampleMatcher cung cấp thông tin chi tiết về cách đối sánh các trường cụ thể. Nó có thể được sử dụng lại trên nhiều Ví dụ.
·
Ví dụ: Một Ví dụ bao gồm đầu dò và Ví dụ về Đối sánh. Nó được sử dụng để tạo truy vấn.
·
Truy vấn theo Ví dụ rất phù hợp cho một số trường hợp sử dụng:
·
Truy vấn kho dữ liệu của bạn với một tập hợp các ràng buộc tĩnh hoặc động.
·
Thường xuyên tái cấu trúc các đối tượng miền mà không phải lo lắng về việc phá vỡ các truy vấn hiện có.
·
Làm việc độc lập với API lưu trữ dữ liệu cơ bản.
·
Truy vấn theo Ví dụ cũng có một số hạn chế:
·
Không hỗ trợ các ràng buộc thuộc tính lồng nhau hoặc nhóm, chẳng hạn như firstname =? 0 hoặc (firstname =? 1 và lastname
=? 2).
·
Chỉ hỗ trợ đối sánh bắt đầu / chứa / kết thúc / regex cho các chuỗi và đối sánh chính xác cho
các loại thuộc tính khác.
·
Trước khi bắt đầu với Truy vấn bằng ví dụ, bạn cần có một đối tượng miền. Để bắt đầu, hãy tạo giao diện cho kho lưu trữ của bạn, như được hiển thị trong ví dụ sau:
Ví dụ 100. Đối tượng Người mẫu
Ví dụ trước cho thấy một đối tượng miền đơn giản. Bạn có thể sử dụng nó để tạo một Ví dụ. Theo mặc định, các trường có giá trị null sẽ bị bỏ qua và các chuỗi được khớp bằng cách sử dụng các giá trị mặc định cụ thể của cửa hàng.
Các ví dụ có
thể được tạo bằng cách sử dụng phương thức của nhà máy hoặc bằng cách sử dụng ExampleMatcher. Ví
dụ là bất biến. Danh sách sau đây cho thấy một ví dụ đơn giản:
Ví dụ 101. Ví dụ đơn giản
Bạn có
thể chạy các truy vấn mẫu bằng cách sử dụng kho lưu trữ. Để làm như vậy, hãy để giao diện kho lưu trữ của bạn mở rộng
QueryByExampleExecutor <T>. Danh sách sau đây hiển thị một đoạn trích từ giao diện QueryByExampleExecutor:
Ví dụ 102. QueryByExampleExecutor
6.6.3. Đối sánh ví dụ
Ví dụ
không giới hạn ở cài đặt mặc định. Bạn có thể chỉ định các giá trị mặc định của riêng mình cho đối sánh chuỗi, xử lý null và cài đặt thuộc tính cụ thể bằng cách sử dụng ExampleMatcher, như được hiển thị trong ví dụ sau:
Ví dụ 103. Đối sánh ví dụ với đối
sánh tùy chỉnh
Theo mặc định, ExampleMatcher
mong đợi tất cả các giá trị được đặt trên đầu dò phải khớp. Nếu bạn muốn nhận kết quả khớp với bất kỳ vị từ nào được xác định ngầm, hãy sử dụng
ExampleMatcher.matchingAny ().
Bạn có
thể chỉ định hành vi cho các
thuộc tính riêng lẻ (chẳng hạn như
"firstname" và
"lastname" hoặc đối với các thuộc tính lồng nhau,
"address.city"). Bạn có
thể điều chỉnh nó với các tùy chọn phù hợp và phân biệt chữ hoa chữ thường, như được hiển thị trong ví dụ sau:
Ví dụ 104. Định cấu hình các tùy chọn so
khớp
Một
cách khác để định cấu hình các tùy chọn so khớp là sử dụng lambdas (được giới thiệu trong Java 8). Cách
tiếp cận này tạo ra một lệnh gọi lại yêu cầu người triển khai sửa đổi trình kết hợp. Bạn không cần trả lại trình so khớp, vì các tùy chọn cấu hình được giữ trong phiên bản so khớp. Ví dụ sau cho thấy một trình so khớp sử dụng lambdas:
Ví dụ 105. Định cấu hình các tùy chọn so
khớp với
lambdas
Các truy vấn được tạo bởi Ví dụ sử dụng chế độ xem cấu hình đã hợp nhất. Cài đặt đối sánh mặc định có thể được đặt ở cấp ExampleMatcher,
trong khi cài đặt
riêng lẻ có thể được áp dụng cho các đường dẫn thuộc tính cụ thể. Cài đặt được đặt trên ExampleMatcher
được kế thừa bởi cài đặt đường dẫn thuộc tính trừ khi chúng được xác định rõ ràng. Cài đặt trên bản vá thuộc tính có mức độ ưu tiên cao hơn cài đặt mặc định. Bảng sau đây mô tả phạm vi của các cài đặt ExampleMatcher khác
nhau:
6.6.4. Chạy một ví
dụ
Trong Spring Data JPA, bạn có thể sử dụng Truy vấn theo Ví dụ với Kho lưu trữ, như được hiển thị trong ví dụ sau:
Ví dụ 106. Truy vấn
theo Ví dụ sử dụng
Kho lưu trữ
Bộ chỉ định thuộc tính chấp nhận tên thuộc tính (chẳng hạn như họ và tên). Bạn có thể điều hướng bằng cách xâu chuỗi các thuộc tính với nhau bằng các dấu chấm (address.city). Bạn cũng có thể điều chỉnh nó bằng các tùy chọn phù hợp và phân biệt chữ hoa chữ thường.
Bảng
sau đây cho thấy các tùy chọn StringMatcher khác nhau mà bạn có thể sử dụng và kết quả của việc sử dụng chúng trên một trường có tên firstname:
6,7. Giao dịch
Theo mặc định, các phương thức CRUD trên các phiên
bản kho lưu trữ được kế thừa từ SimpleJpaRepository
là giao dịch. Đối với các hoạt động đọc, cờ cấu hình giao dịch readOnly được đặt thành true. Tất cả những thứ khác được định cấu hình bằng @Transactional thuần túy để cấu hình giao dịch mặc định được áp dụng. Các phương thức kho lưu trữ được hỗ trợ bởi các phân đoạn kho lưu trữ giao dịch kế thừa các thuộc tính giao dịch từ phương thức phân mảnh thực tế.
Nếu bạn cần chỉnh sửa cấu hình giao dịch cho một trong các phương thức được khai báo trong kho
lưu trữ, hãy khai báo lại phương thức đó trong giao diện kho lưu trữ của bạn, như sau:
Ví dụ 107. Cấu hình giao dịch
tùy chỉnh
cho CRUD
Một
cách khác để
thay đổi hành vi giao dịch là sử dụng một mặt tiền hoặc triển khai dịch vụ (thường) bao gồm nhiều hơn một kho lưu trữ. Mục đích của nó là xác định ranh giới giao dịch cho các hoạt động không phải CRUD. Ví dụ sau đây
cho thấy cách sử dụng một mặt tiền như vậy cho nhiều kho lưu trữ:
Ví dụ 108. Sử dụng một mặt tiền để xác định các giao dịch
cho nhiều lệnh gọi
kho lưu trữ
Ví dụ này
khiến lệnh gọi addRoleToAllUsers
(…) chạy bên trong một giao dịch (tham gia vào một giao dịch hiện có hoặc tạo một giao dịch mới nếu chưa có giao dịch nào đang chạy). Cấu hình giao dịch tại các kho lưu trữ sau đó bị bỏ qua, vì cấu hình giao dịch bên ngoài xác định cấu hình thực sự được sử dụng. Lưu ý rằng bạn phải kích hoạt <tx: annotation-driven /> hoặc sử dụng
@EnableTransactionManagement một
cách rõ ràng để cấu hình mặt tiền hoạt động dựa trên chú thích. Ví
dụ này giả sử bạn sử dụng tính năng quét thành phần.
Lưu ý rằng lệnh gọi lưu không
hoàn toàn cần thiết theo quan điểm của JPA, nhưng vẫn nên ở đó để duy trì tính trừu tượng của kho lưu trữ được cung cấp bởi Spring Data.
6.7.1. Các phương
pháp
truy vấn
giao dịch
Để cho
phép các phương
thức truy vấn của bạn được giao dịch, hãy sử dụng @Transactional tại giao diện kho lưu trữ mà bạn xác định, như được hiển thị trong ví dụ sau:
Ví dụ 109. Sử dụng @Transactional tại
các phương
thức
truy vấn
6,8. Khóa
Để chỉ định chế độ khóa được sử dụng, bạn có thể sử dụng chú thích @Lock
trên các phương
thức truy vấn, như được hiển thị trong ví dụ sau:
Ví dụ 110. Định nghĩa siêu dữ liệu khóa trên các phương
thức
truy vấn
Khai báo phương pháp này làm
cho truy vấn được kích hoạt được trang bị LockModeType of
READ. Bạn cũng có thể xác định khóa cho các phương thức CRUD bằng cách khai báo lại chúng trong giao diện kho lưu trữ của mình và thêm chú
thích @Lock, như được hiển thị trong ví dụ sau:
Ví dụ
111. Định nghĩa siêu dữ liệu khóa trên các phương thức CRUD
6,9. Kiểm toán
6.9.1. Khái niệm cơ bản
Spring Data cung cấp hỗ trợ tinh vi để theo dõi minh bạch ai đã tạo hoặc thay đổi một thực thể và khi nào thay đổi xảy ra. Để được hưởng lợi từ chức năng đó, bạn phải trang bị cho các lớp thực thể của mình siêu dữ liệu kiểm tra có thể được xác định bằng cách sử dụng chú thích hoặc bằng cách triển khai giao diện. Ngoài ra, kiểm tra phải được kích hoạt thông qua cấu hình Chú thích hoặc cấu hình XML để đăng ký các thành phần cơ sở hạ tầng được yêu cầu. Vui lòng tham khảo phần dành riêng cho cửa hàng để biết các mẫu cấu hình.
Siêu dữ liệu kiểm tra dựa trên chú thích
Chúng tôi cung cấp @CreateBy và @LastModifiedBy để nắm bắt người dùng đã tạo hoặc sửa đổi thực thể cũng như @CreateDate và @LastModifiedDate để nắm bắt thời điểm thay đổi xảy ra.
Ví dụ 112. Đơn vị được kiểm toán
Như bạn có thể thấy, các chú thích có
thể được áp dụng một cách chọn lọc, tùy thuộc vào thông tin bạn muốn nắm bắt. Các chú thích ghi
lại thời điểm các thay đổi được thực hiện có thể được sử dụng trên các thuộc tính của loại Joda-Time,
DateTime, Ngày và Lịch
Java kế thừa, các loại ngày và giờ JDK8 và Long hoặc Long.
Siêu dữ liệu kiểm tra không nhất thiết phải tồn tại trong thực thể cấp cơ sở nhưng có thể được thêm vào một thực thể được nhúng (tùy thuộc vào cửa hàng thực tế đang được sử dụng), như được hiển thị trong phần bên dưới.
Ví dụ 113. Siêu dữ liệu kiểm
tra trong thực thể được
nhúng
Siêu dữ liệu kiểm toán dựa trên giao diện
Trong trường hợp bạn không muốn sử dụng chú thích để xác định siêu dữ liệu kiểm tra, bạn có thể để lớp miền của mình triển khai giao diện Auditable. Nó cho
thấy các phương pháp setter cho tất cả các thuộc tính kiểm toán.
Ngoài ra còn có một lớp cơ sở tiện lợi, AbstractAuditable, mà bạn có thể mở rộng để tránh phải triển khai các phương thức giao diện theo cách thủ công. Làm như vậy sẽ tăng sự kết hợp các lớp miền của bạn với Dữ liệu mùa xuân, đây có thể là điều bạn muốn tránh. Thông thường, cách xác định siêu dữ liệu kiểm tra dựa trên chú thích được ưu tiên hơn vì nó ít xâm lấn hơn và
linh hoạt hơn.
AuditorAware
Trong trường hợp bạn sử dụng @CreateBy hoặc @LastModifiedBy, cơ sở hạ tầng kiểm toán bằng cách nào đó cần phải biết về nguyên tắc chính hiện tại. Để làm như vậy, chúng tôi cung cấp giao diện AuditorAware
<T> SPI mà bạn phải triển khai để cho cơ sở hạ tầng biết người dùng hoặc hệ thống hiện tại tương tác với ứng dụng là ai. Kiểu chung T xác định loại thuộc tính được chú thích bằng @CreateBy hoặc @LastModifiedBy phải là.
Ví dụ sau
cho thấy cách triển khai giao diện sử dụng đối tượng Xác thực của Spring Security:
Ví dụ 114. Triển
khai AuditorAware dựa
trên Spring Security
Việc
triển khai truy cập đối tượng Xác thực do Spring Security
cung cấp và tra cứu phiên bản UserDetails tùy chỉnh mà bạn đã tạo trong quá trình triển khai
UserDetailsService của
mình. Ở đây, chúng tôi giả định rằng bạn đang tiết lộ người dùng miền thông qua triển khai UserDetails nhưng dựa trên Xác thực được tìm thấy, bạn cũng có thể tra cứu nó từ bất kỳ đâu.
ReactiveAuditorAware
Khi sử dụng cơ sở hạ tầng phản ứng, bạn có thể muốn sử dụng thông tin theo ngữ cảnh để cung cấp thông tin @CreateBy
hoặc @LastModifiedBy.
Chúng tôi cung cấp
giao diện ReactiveAuditorAware
<T> SPI mà bạn phải triển khai để cho cơ sở hạ tầng biết người dùng hoặc hệ thống hiện tại tương tác với ứng dụng là ai. Kiểu chung T xác định loại thuộc tính được chú thích bằng @CreateBy hoặc @LastModifiedBy phải là.
Ví dụ sau
cho thấy cách triển khai giao diện sử dụng đối tượng Xác thực của Spring Security phản ứng:
Ví dụ 115. Triển
khai ReactiveAuditorAware dựa trên Spring Security
Việc
triển khai truy cập vào xác thực đối tượng do Spring Security
cung cấp và tra cứu UserDetails phiên bản tùy chỉnh mà bạn đã tạo ra trong quá trình triển khai
UserDetailsService của
mình. Ở đây, chúng tôi giả định rằng bạn đang tiết lộ người dùng miền thông qua phát triển UserDetails nhưng dựa trên Xác thực được tìm thấy, bạn cũng có thể tìm kiếm nó từ bất kỳ đâu. :
leveloffset: -1
6.9.2. JPA kiểm
toán
Chung thanh toán cấu
hình
Spring Data JPA cung cấp một trình thực thi có thể được sử dụng để kích hoạt công việc kiểm tra thông tin thập phân. Trước tiên, bạn phải đăng ký AuditingEntityListener để được sử dụng cho tất cả các thực thi trong liên tục ngữ cảnh bên trong tệp orm.xml của bạn, như được hiển thị trong ví dụ sau:
Ví dụ 116. Cấu hình kiểm
tra orm.xml
Bạn cũng có thể bật AuditingEntityListener trên cơ sở mỗi tổ chức bằng cách sử dụng chú thích
@EntityListener, như
sau:
Với
orm.xml được sửa đổi phù hợp và
spring-domains.jar trên classpath, việc kích hoạt chức năng kiểm tra là vấn đề của việc thêm phần tử không gian tên kiểm tra Spring Data JPA
vào cấu hình của bạn, như sau:
Ví dụ 117. Kích hoạt kiểm
tra bằng
cách sử dụng cấu
hình XML
Từ
Spring Data JPA 1.5, bạn có
thể bật kiểm tra bằng cách chú thích một cấu hình lớp với chú thích @EnableJpaAuditing.
Bạn vẫn phải sửa đổi file orm.xml và có
spring-domains.jar trên classpath. Ví dụ sau cho cách sử dụng chú thích @EnableJpaAuditing:
Ví dụ 118. Kích hoạt kiểm
tra bằng cấu
hình Java
Nếu bạn để lộ một bean loại AuditorAware với ApplicationContext,
cơ sở hạ tầng kiểm tra sẽ tự động chọn nó và sử dụng nó để xác định người dùng hiện tại được đặt trên các loại miền. Nếu bạn có nhiều triển khai được đăng ký trong ApplicationContext, bạn có thể chọn một triển khai sẽ được sử dụng bằng cách thiết lập rõ ràng thuộc tính
auditorAwareRef của
@EnableJpaAuditing.
6.10. Các cân nhắc
khác
6.10.1. Sử dụng
JpaContext trong Triển
khai Tùy chỉnh
Khi làm việc với nhiều cá thể EntityManager và triển khai kho lưu trữ tùy chỉnh, bạn cần chuyển EntityManager chính
xác vào lớp
triển khai kho lưu trữ. Bạn có thể làm như vậy bằng cách đặt tên rõ ràng cho
EntityManager trong chú thích @PersistenceContext hoặc, nếu EntityManager là
@Autowosystem, bằng
cách sử dụng @Qualifier.
Kể từ Spring Data JPA 1.9,
Spring Data JPA bao gồm một lớp gọi là JpaContext cho
phép bạn lấy EntityManager theo
lớp miền được quản lý, giả sử rằng nó chỉ được quản lý bởi một trong các phiên bản EntityManager trong
ứng dụng. Ví dụ sau đây cho thấy cách sử dụng JpaContext trong một kho lưu trữ tùy chỉnh:
Ví dụ 119. Sử dụng JpaContext trong triển
khai kho lưu trữ tùy
chỉnh
Ưu điểm của cách tiếp cận này là, nếu loại miền được gán cho một đơn vị lâu dài khác, kho lưu trữ không cần phải được chạm vào để thay đổi tham chiếu đến đơn vị lâu dài.
6.10.2. Hợp nhất
các đơn vị bền vững
Spring hỗ trợ có nhiều đơn vị độ bền. Tuy nhiên, đôi khi, bạn có thể muốn mô-đun hóa ứng dụng của mình nhưng vẫn đảm bảo rằng tất cả các mô-đun này chạy bên trong một đơn vị bền bỉ duy nhất. Để kích hoạt hành vi đó,
Spring Data JPA cung cấp
triển khai
PersistenceUnitManager tự động hợp nhất các đơn vị bền vững dựa trên tên của chúng, như được hiển thị trong ví dụ sau:
Ví dụ 120. Sử dụng MergingPersistenceUnitmanager
Quét Classpath cho các lớp
@Entity và tệp
ánh xạ JPA
Thiết lập JPA thuần túy yêu cầu tất cả các lớp thực thể được ánh xạ chú thích phải được liệt kê trong orm.xml. Điều tương tự cũng áp dụng cho các tệp ánh xạ XML. Spring Data JPA cung cấp một
ClasspathScanningPersistenceUnitPostProcessor để cấu hình gói cơ sở và tùy chọn lấy mẫu tên tệp ánh xạ. Sau đó, nó sẽ quét gói đã cho
để tìm các lớp được chú thích bằng @Entity hoặc @MappedSuperclass,
tải các tệp cấu hình phù hợp với mẫu tên tệp và đưa chúng vào cấu hình JPA. Bộ xử lý hậu kỳ phải được định cấu hình như sau:
Ví dụ 121. Sử dụng
ClasspathScanningPersistenceUnitPostProcessor
6.10.3. Tích hợp
CDI
Các phiên bản của giao diện kho lưu trữ thường được tạo bởi một vùng chứa, trong đó
Spring là lựa chọn tự nhiên nhất khi làm việc với Spring Data. Spring
cung cấp hỗ trợ tinh vi để tạo các cá thể bean, như được ghi lại trong Tạo các Phiên bản Kho lưu trữ. Kể từ phiên bản 1.1.0, Spring Data
JPA đi kèm với phần mở rộng CDI tùy chỉnh cho phép sử dụng tính trừu tượng của kho lưu trữ trong môi trường CDI. Phần mở rộng là một phần của JAR. Để kích hoạt nó, hãy bao gồm Spring Data JPA JAR trên classpath của bạn.
Bây giờ bạn có thể thiết lập cơ sở hạ tầng bằng cách triển khai CDI Producer
cho EntityManagerFactory và EntityManager, như được minh họa trong ví dụ sau:
Thiết lập cần thiết có thể khác nhau tùy thuộc vào môi trường JavaEE. Bạn có thể không cần làm gì khác hơn là khai báo lại EntityManager dưới dạng bean CDI, như sau:
Trong ví dụ trước, vùng chứa phải có khả năng tự tạo JPA EntityManagers. Tất cả những gì cấu hình làm là tái xuất JPA EntityManager dưới dạng một bean CDI.
Phần mở rộng Spring Data JPA
CDI chọn tất cả các phiên bản EntityManager có sẵn dưới dạng các bean CDI và tạo một proxy cho kho lưu trữ Spring Data bất cứ khi nào vùng chứa yêu cầu một bean thuộc loại kho lưu trữ. Do đó, việc có được một phiên bản của kho lưu trữ Dữ liệu mùa xuân là vấn đề khai báo thuộc tính @Injected, như thể hiện trong ví dụ sau:
- Tham chiếu không gian tên:
Phần <repositories />
tử kích hoạt thiết lập cơ sở hạ tầng kho lưu trữ Dữ liệu mùa xuân. Thuộc tính quan trọng nhất là base-package
, xác định gói để quét các giao diện của kho lưu trữ Dữ liệu Mùa xuân. Xem “ Cấu hình XML ”. Bảng sau đây mô tả các thuộc tính của <repositories />
phần 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ần <populator
/>
tử cho phép đưa vào kho lưu trữ dữ liệu thông qua cơ sở hạ tầng kho lưu trữ Dữ liệu 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ợ
Bảng sau liệt kê các từ khóa chủ đề thường được hỗ trợ bởi cơ chế dẫn xuất truy vấn của kho lưu trữ Dữ liệu Mùa xuân để diễn đạt vị từ. 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ợ, bởi 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 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ể.
Ngoài các vị từ bộ lọc, 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 JpaRepository
chẳng hạn. Làm thế nào tôi
có thể đạt được chúng?
Bạn có thể sử dụng CustomizableTraceInterceptor
Spring
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 SessionFactory
bằ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ế AnnotationSessionFactoryBean
bằng HibernateJpaSessionFactoryBean
, như sau:
Ví dụ 122. Tra SessionFactory
từ 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-dates
thuộc tính của auditing
phầ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