Để có mô tả dài hơn, bạn có thể đọc bài viết Chống mô hình phiên mở trong chế độ xem của tôi . Nếu không, đây là bản tóm tắt lý do tại sao bạn không nên sử dụng Open Session In View.
Mở phiên trong chế độ xem có một cách tiếp cận xấu để tìm nạp dữ liệu. 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, nó 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.
- 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
.
- Tìm
PostDAO
nạp danh sách các Post
thực thể mà không cần khởi tạo bất kỳ liên kết lười biếng nào.
- 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ỗ hổng 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, điều này 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 ứng dụng được triển khai 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ế nhạo 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ó thể được giữ trong suốt giai đoạn kết xuất giao diện người dùng (tùy thuộc vào chế độ phát hành kết nối của bạn), đ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. Càng giữ nhiều kết nối, thì càng có nhiều yêu cầu đồng thời khác sẽ phải đợi để nhận được kết nối từ nhóm.
Vì vậy, hoặc bạn bị giữ kết nối quá lâu, hoặc bạn có được / giải phóng nhiều kết nối cho một yêu cầu HTTP duy nhất, do đó gây áp lực lên nhóm kết nối cơ bản và hạn chế khả năng mở rộng.
Khởi động mùa xuân
Rất tiếc, Open Session in View được bật theo mặc định trong Spring Boot .
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 .