我有RestController从服务调用方法。方法将User添加到PostresSQL数据库,该数据库最多有20个连接。
@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;
}
}
服务中的方法由Spring Transactional注释,在持久化数据方法返回CompletableFuture之后,在其中进行了一些长操作。我从多个线程(大约100个)同时调用方法“/ user”。
@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";
});
}
如果阻塞当前线程的代码行“voidCompletableFuture.get()”被调用,那么只有20个并发请求正在工作,并且通过最大连接数将数据添加到数据库。另一个线程中有异常:
Caused by: java.sql.SQLTransientConnectionException: Connection is not available, request timed out after 30000ms.
如果我删除这行代码,那么每个请求都在工作,并按预期将数据添加到数据库。我认为这是因为如果我之后调用future.get(),则在方法“public Future addUser(UserInfo userInfo)”结束后事务未完成。 也许有人知道为什么Spring和CompletableFuture以这样的方式工作,或者可能还有另一个答案?为什么阻止CompletableFuture会影响另一种方法中的Transaction结束?如果请求方法中存在阻塞,为什么方法不完成当前事务而不释放连接。
答案 0 :(得分:1)
添加spring.jpa.open-in-view=false
事务后,在方法setUser()
之后开始停止,而不是在请求的整个过程中停止。
来自文档:
spring.jpa.open-in-view=true - Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the thread for the entire processing of the request.