在SpringBoot中管理并发POST请求最佳实践

时间:2020-11-10 17:15:36

标签: java spring rest post http-post

我正在使用SpringBoot构建REST-API并使用此Controller。

foo

我想确保API使用者不会向具有相同@RestController class EmployeeController { private final EmployeeRepository repository; EmployeeController(EmployeeRepository repository) { this.repository = repository; } @GetMapping("/employees") List<Employee> all() { return repository.findAll(); } @PostMapping("/employees") Employee newEmployee(@RequestBody Employee newEmployee) { return repository.save(newEmployee); } 的多个并发POST请求发送垃圾邮件。我知道可以在保存数据库之前检查该实体是否已经存在,但是恐怕性能会很差。我还已经注意到,您可以在实体中使用Employee之类的注释来对现有Entity的更新进行更多保存。

但是在Spring中,还有没有一种方法或最佳实践来处理带有潜在新实体的POST请求?

1 个答案:

答案 0 :(得分:0)

您对POST /employees端点有什么样的请求吞吐量?虽然性能很重要,但过早的优化几乎总是会导致您的代码比所需要的更丑陋,从而几乎没有收益。

按照您当前的代码立场,多个并发POST /employees请求将以先到先得的原则结束,在此基础上,您的应用程序中具有给定UNIQUE约束的第一位用户(有望实施)由您的基础DBMS创建),此后(针对同一用户)的所有其他操作都会由于例如ConstraintViolationException(映射到例如DataIntegrityViolationException)。从这个角度来看(只要您没有复杂的分布式DBMS设置),仍然可以保证数据的一致性。

当然,缺点是将返回的错误消息是:

  1. 特定于供应商并泄漏了底层实现(例如,我们正在向客户端显示我们正在使用Hibernate)
  2. 客户端可能无法解析。

如果相反,请将实现更改为以下内容:

  @PostMapping("/employees")
  Employee newEmployee(@RequestBody Employee newEmployee) {
    verifyEmployeeDoesNotExist(newEmployee);
    return repository.save(newEmployee);
  }

  private void verifyUserDoesNotExist(Employee employee) {
    if (repository.exists(newEmployee) {
      throw new EmployeeAlreadyExistsException("Employee " + newEmployee.getName() + " already exists";
    }
  }

然后,您可以更轻松地控制端点和基础流程的控制流,这有可能允许更容易消化的异常处理。甚至可以通过添加例如自定义异常,其中还包含一些预定义的error code代码,例如error 409 code 1010 Employee already exists

当然,Spring为Hibernate内置的异常转换(例如HibernateExceptionTranslator)对于您的用例可能已经足够好了,甚至可以扩展,甚至可以泛化此扩展。

最后,最佳实践是使您的代码干净,可读和可维护。然后开始添加功能来监视您的代码。 之后,只有如果您对性能有疑问,仍可以对其进行优化。