我正在使用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请求?
答案 0 :(得分:0)
您对POST /employees
端点有什么样的请求吞吐量?虽然性能很重要,但过早的优化几乎总是会导致您的代码比所需要的更丑陋,从而几乎没有收益。
按照您当前的代码立场,多个并发POST /employees
请求将以先到先得的原则结束,在此基础上,您的应用程序中具有给定UNIQUE
约束的第一位用户(有望实施)由您的基础DBMS创建),此后(针对同一用户)的所有其他操作都会由于例如ConstraintViolationException
(映射到例如DataIntegrityViolationException
)。从这个角度来看(只要您没有复杂的分布式DBMS设置),仍然可以保证数据的一致性。
当然,缺点是将返回的错误消息是:
如果相反,请将实现更改为以下内容:
@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
)对于您的用例可能已经足够好了,甚至可以扩展,甚至可以泛化此扩展。
最后,最佳实践是使您的代码干净,可读和可维护。然后开始添加功能来监视您的代码。 之后,只有如果您对性能有疑问,仍可以对其进行优化。