OSIV Anti-Pattern
Thay vì để lớp nghiệp vụ quyết định cách tốt nhất để tìm nạp tất cả các liên kết mà lớp Chế độ xem cần, OSIV (Phiên mở trong Chế độ xem) buộc Ngữ cảnh bền vững luôn mở để lớp Chế độ xem có thể kích hoạt khởi tạo Proxy, như minh họa bằng sơ đồ sau.
- Các
OpenSessionInViewFilter
cuộc gọi openSession
phương thức của cơ sở SessionFactory
và nhận được một mới Session
.
- Các
Session
ràng buộc với TransactionSynchronizationManager
.
- Các
OpenSessionInViewFilter
gọi doFilter
của javax.servlet.FilterChain
tham chiếu đối tượng và yêu cầu được tiếp tục chế biến
- Nó
DispatcherServlet
được gọi và nó định tuyến yêu cầu HTTP đến bên dưới PostController
.
- Các
PostController
lệnh gọi PostService
để lấy danh sách các Post
thực thể.
- Giao dịch
PostService
mở ra một giao dịch mới và HibernateTransactionManager
sử dụng lại giao dịch Session
đã được mở bởi OpenSessionInViewFilter
.
- Các
PostDAO
fetches các danh sách các Post
thực thể mà không cần khởi tạo bất cứ tổ chức lười biếng.
- Giao dịch
PostService
cam kết giao dịch cơ bản, nhưng Session
không bị đóng vì nó được mở bên ngoài.
- Các
DispatcherServlet
render giao diện người dùng, trong đó, đến lượt nó, điều hướng các hiệp hội lười biếng và gây nên khởi tạo của họ bắt đầu.
- Có
OpenSessionInViewFilter
thể đóng Session
, và kết nối cơ sở dữ liệu cơ bản cũng được phát hành.
Thoạt nhìn, điều này có vẻ không phải là một việc tồi tệ để làm, nhưng một khi bạn xem nó từ góc độ cơ sở dữ liệu, một loạt lỗi bắt đầu trở nên rõ ràng hơn.
Lớp dịch vụ mở và đóng một giao dịch cơ sở dữ liệu, nhưng sau đó, không có giao dịch rõ ràng nào diễn ra. Vì lý do này, mọi câu lệnh bổ sung được đưa ra từ giai đoạn kết xuất giao diện người dùng được thực thi ở chế độ cam kết tự động. Tự động cam kết gây áp lực lên máy chủ cơ sở dữ liệu vì mỗi câu lệnh phải chuyển nhật ký giao dịch vào đĩa, do đó gây ra nhiều lưu lượng I / O trên phía cơ sở dữ liệu. Một tối ưu hóa sẽ là đánh dấu Connection
là chỉ đọc sẽ cho phép máy chủ cơ sở dữ liệu tránh ghi vào nhật ký giao dịch.
Không có sự tách biệt của các mối quan tâm nữa vì các câu lệnh được tạo ra bởi cả lớp dịch vụ và quá trình kết xuất giao diện người dùng. Viết các bài kiểm tra tích hợp xác nhận số lượng câu lệnh được tạo yêu cầu phải đi qua tất cả các lớp (web, dịch vụ, DAO) trong khi triển khai ứng dụng trên vùng chứa web. Ngay cả khi sử dụng cơ sở dữ liệu trong bộ nhớ (ví dụ: HSQLDB) và máy chủ web nhẹ (ví dụ: Jetty), các thử nghiệm tích hợp này sẽ thực thi chậm hơn so với nếu các lớp được tách biệt và các thử nghiệm tích hợp phía sau sử dụng cơ sở dữ liệu, trong khi các bài kiểm tra tích hợp front-end đang chế giễu hoàn toàn lớp dịch vụ.
Lớp giao diện người dùng được giới hạn trong việc điều hướng các liên kết có thể kích hoạt N + 1 sự cố truy vấn . Mặc dù Hibernate cung cấp @BatchSize
các liên kết tìm nạp theo lô và FetchMode.SUBSELECT
để đối phó với trường hợp này, các chú thích đang ảnh hưởng đến kế hoạch tìm nạp mặc định, vì vậy chúng được áp dụng cho mọi trường hợp sử dụng kinh doanh. Vì lý do này, truy vấn lớp truy cập dữ liệu phù hợp hơn nhiều vì nó có thể được điều chỉnh cho phù hợp với các yêu cầu tìm nạp dữ liệu ca sử dụng hiện tại.
Cuối cùng nhưng không kém phần quan trọng, kết nối cơ sở dữ liệu được tổ chức trong suốt giai đoạn kết xuất giao diện người dùng, điều này làm tăng thời gian thuê kết nối và hạn chế thông lượng giao dịch tổng thể do tắc nghẽn trên nhóm kết nối cơ sở dữ liệu. Kết nối càng được giữ, thì càng có nhiều yêu cầu đồng thời khác sẽ phải chờ để nhận được kết nối từ nhóm.
Spring Boot và OSIV
Thật không may, OSIV (Open Session in View) được bật theo mặc định trong Spring Boot và OSIV thực sự là một ý tưởng tồi từ góc độ hiệu suất và khả năng mở rộng .
Vì vậy, hãy đảm bảo rằng trong application.properties
tệp cấu hình, bạn có mục nhập sau:
spring.jpa.open-in-view=false
Thao tác này sẽ vô hiệu hóa OSIV để bạn có thể xử lý LazyInitializationException
đúng cách .
Bắt đầu với phiên bản 2.0, Spring Boot đưa ra cảnh báo khi OSIV được bật theo mặc định, vì vậy bạn có thể phát hiện ra sự cố này rất lâu trước khi nó ảnh hưởng đến hệ thống sản xuất.
Để biết thêm chi tiết về OSIV, hãy xem bài viết này .