Overview: Spring Open Session in View is one of the transactional patterns, for binding Hibernate session/JPA Entity Manager to user request life-cycle. Spring MVC comes with one of the implementations for an open session in view pattern, named OpenSessionInViewInterceptor or OpenSessionInViewFilter to work with lazy associations, and improving hire Java developer productivity.
Introduction:
For a better understanding of Open Session in View, let’s suppose we have an incoming request, and spring MVC will do the below things on behalf of you:
If we understand the overview of this process, it can boosts the developer productivity as session creation/binding the session/ closing the session will be done by framework.
But sometimes Open Session in View will also cause performance issues mainly in production.
Spring Boot: By default Open Session in View, is enabled.
Since Spring Boot 2.0, if this is enabled, it will log the below warning in the console.
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
We can also disable this property by setting spring.jpa.open-in-view to false.
Pros and Cons of Open Session in View (OSIV):
Pros of OSIV:
Cons of OSIV:
Lazy initialization:
For better understanding the OSIV, let’s consider the example, user is one of the entities, class, having a set of permissions.
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
private String username;
@ElementCollection
private Set<String> permissions;
// getters and setters
}```
And sample Service class for finding the user by using username:
```@Service
public class SimpleUserService implements UserService {
private final UserRepository userRepository;
public SimpleUserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional(readOnly = true)
public Optional<User> findOne(String username) {
return userRepository.findByUsername(username);
}
}```
And Sample User Controller will look like below:
```@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{username}")
public ResponseEntity<?> findOne(@PathVariable String username) {
return userService
.findOne(username)
.map(DetailedUserDto::fromEntity)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
}```
Here, based on the username path-variable, it will fetch the user from database.
Below is the JUnit test case for testing this:
```@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class UserControllerIntegrationTest {
@Autowired
private UserRepository userRepository;
@Autowired
private MockMvc mockMvc;
@BeforeEach
void setUp() {
User user = new User();
user.setUsername("root");
user.setPermissions(new HashSet<>(Arrays.asList("PERM_READ", "PERM_WRITE")));
userRepository.save(user);
}
@Test
Void givenTheUserExists_WhenOsivIsEnabled_ThenLazyInitWorksEverywhere() throws Exception {
mockMvc.perform(get("/users/root"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("root"))
.andExpect(jsonPath("$.permissions", containsInAnyOrder("PERM_READ", "PERM_WRITE")));
}
}```
If we execute this, it will be successful, if the OSIV is not configured then it will fail, as for permission property, it will throw LazyInitializationException exception.
**Alternatives to OSIV:**
1) A developer can handle all dependencies to load in transaction context using like Hibernate.initialize(user.getPermissions()).
2) We can JPA 2 Entity graphs for fetching all dependent entities.
3) We can use the JOIN FETCH keyword to fetch all nested properties.
Conclusion: we learned about Open Session in View (OSIV), pros and cons of it, and also how Spring boot internally uses OSIV, and what is the alternative to OSIV.
#Spring #MVC #Java #Developer