I have RestController which calls method from service. Method adds User to PostresSQL database, which has maximum of 20 connections.
@RestController
public class Controller {
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String addUser(@RequestBody UserInfo userInfo) {
Future<String> completableFuture = userService.addUser(userInfo);
String answer = voidCompletableFuture.get();
return answer;
}
}
Method in service is annotated by Spring Transactional, after persisting data method returns CompletableFuture, inside of it some long operation. I call method "/user" simultaneously from multiple threads (about 100).
@Transactional
public Future<String> addUser(UserInfo userInfo) {
userDao.persist(userInfo);
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(10000);
return "Result";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Error";
});
}
If line of code "voidCompletableFuture.get()", which blocking current thread, is called then only 20 simultaneous request is working and adding data to database by number of maximum connections. There is exception in another threads:
Caused by: java.sql.SQLTransientConnectionException: Connection is not available, request timed out after 30000ms.
If I remove this line of code, then every request is working and adds data to database as expected. I think it is because Transaction not completed after end of method "public Future addUser(UserInfo userInfo)" if I call future.get() after. Maybe someone knows why Spring and CompletableFuture works in such a way or maybe there is another answer? Why blocking of CompletableFuture affects end of Transaction in another method? Why method not completing current transaction and not releasing connection if there is a block inside request method.
After adding spring.jpa.open-in-view=false
transaction begin to stop after method setUser()
and not in entire process of the request.
From documentation:
spring.jpa.open-in-view=true - Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request.