Open Session In View in Spring Boot: Hidden Threat
Everyone here is right, each in his own way, and therefore everyone is wrong here.
"The Tale of Troika" (A. and B. Strugatsky)
If you are using Spring Data JPA, after updating to Spring Boot 2, when starting the application, you may notice a new warning in the log:
spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning.
In this article I will try to explain what it means, who is to blame and what to do.
To raise a full-fledged Spring Boot application, only one annotation is required
@SpringBootApplication. In order to make this possible, the framework uses a large number of autoconfigurations and default settings. Moreover, to work out of the box, Spring Boot developers had to choose certain concepts of application development from several alternative options for each, so that the user does not have to choose them explicitly. On the one hand, this is good for a quick start and easy development, but on the other hand, after a while it may turn out that some default concept / paradigm / setting is not suitable for the project, and to reject it you will have to redo much. One such concept is the Open Session In View (OSIV) mode , which is included by default in Spring Boot.
In this mode, the Hibernate session is kept open all the time while processing an HTTP request, including the step of creating a view (JSON resource) or an HTML page. This makes it possible to lazy load data in the presentation layer after the transaction commit in the business logic layer. For example, we request an entity from a DB
Article. The article should be displayed along with comments. OSIV, when rendering HTML, simply calls the entity method
getComments(), and comments will be loaded with a separate request. When OSIV mode is disabled, we get it
LazyInitializationException, since the session is already closed, and the entity is
Articleno longer managed by Hibernate. Most Hibernate developers have come across
LazyInitializationException; OSIV allows you to avoid it by loading data as needed at any stage of processing an HTTP request.
OSIV in Spring Boot is implemented using a web query interceptor class
OpenEntityManagerInViewInterceptor. Unlike pure Spring, here it is enabled by default.
OSIV is considered antipattern. Vlad Mihalcea, one of the developers of Hibernate, explained his best practices in his article: The Open Session In Anti-Pattern . Key points:
- Queries to the database without a transaction work in the auto-commit mode, heavily loading it.
- There is no division of responsibility; any layer of the application can generate SQL queries, which makes testing difficult.
- A n + 1 problem occurs when each collection associated with an entity is loaded with a separate query.
- Long connections to the database again increase the load on it and reduce the bandwidth.
These are rather unpleasant problems of the OSIV mode and seemingly strong arguments for not using it. However, in the default shutdown request , Spring Boot developers also made a strong case for why OSIV should be enabled for new projects:
- Backward compatibility. Existing applications when upgrading to Spring Boot 2 could encounter bugs and bugs due to disabled OSIV. To avoid this, you only need to set a single value
spring.jpa.open-in-view, but this will also make it difficult to switch to the new version.
- For Spring Boot, ease of use for beginners and a quick start are important. If you turn off OSIV, it may be unclear for beginners why such an intuitively expected thing does not work, like getting a collection of related elements when accessing an entity method. Instead, the user will receive
LazyInitializationException, this will slow down his path to the running application.
- OSIV allows you to increase the simplicity of the code, convenience and speed of development.
- It is hard to find simple examples of how an application should be built without OSIV.
- Without OSIV, the business logic layer needs to know how the data will be represented in the UI, that is, what DTOs it needs or what related data should be loaded along with the root entity. This is again the lack of shared responsibility.
So, we can distinguish two views on this problem. From the point of view of the database architect (DBA), Open Session In View is certainly unacceptable, since the interaction of the application with the database is not optimally organized and causes an increased load. But we often use less optimal solutions for the sake of speed, ease of development and ease of learning tools - we write in managed languages, use text data formats for networking, and so on. From the perspective of a framework developer to simplify the development and quick start of newbies, OSIV allows you to reduce the cognitive load, the number of concepts needed to start developing an application. If the developer chose JPA, he has already agreed to a slight decrease in performance in exchange for ease of development. JPA helps to make friends object and relational data models. When working in an object style to obtain related elements, we simply refer to the method of the entity (even if in the presentation layer), this is simple, logical and intuitively expected, although this simplicity is deceptive.
There are many examples and tutorials for working in Open Session In View mode. The architecture is generally clear: the service layer requests the JPA entity, the view layer serializes it to JSON directly, via an intermediate DTO, or uses data from it to render the HTML page.
Less clear how to work without OSIV. One of the Spring developers in the above-mentioned request complains about this, they say a lot of cries about the anti-pattern, but there are no simple examples of how to live without it. In this embodiment, entities can only be used for writing, and for reading, numerous DTOs, separate for each data set in the UI, which are mapped directly from the database. Or custom SQL queries with a join-s description of the necessary related collections for a particular web query. That is, more boilerplate and a description of the needs of the UI in the business logic layer. With the OSIV mode disabled, the JPA abstraction starts to flow, the application describes more technical details of interaction with the database.
Thus, developing with OSIV is simpler. But the problem is that if in the future you want to abandon it, you will have to redo a lot, the concept of working with the database in the project by setting one property will not change. You may have to redo the entire application architecture. However, abandoning OSIV can be a premature optimization that will slow development speed, which can be critical for a startup, for example. You can use OSIV and optimize database queries only in the slowest places. For example, requests for entity collections are most affected by the n + 1 problem, when each entity pulls several requests for related collections.
So, if you want to do it right, you need to develop without OSIV. But if development speed and simplicity of code are important, you can use this mode, resigning yourself to some loss of performance.
The main thing is that this performance problem does not turn into a huge technical debt in a few years. The situation is doubly dangerous when developers do not even suspect that they are accumulating this debt, because Spring Boot silently chose the Open Session In View concept for them. Therefore, it is excellent that as a result of the above request, it was decided to output to the log a warning about the mode used, given by me at the beginning of the article.
I hope that the warning and this article about my will help developers make a more informed decision - whether to use the concept of Open Session In View in the application on Spring Boot. I led and discussed the main arguments for and against, I also advise you to read the original discussion. This problem shows that a large number of autoconfigurations and defaults in Spring / Spring Boot can be dangerous for inattentive developers.
Do you use OSIV in Spring Boot apps? If not, how is the architecture of the interaction between the presentation layer and the database organized? What tricks and / or libraries are used for this?