如何解决Spring Boot控制器可防止在mongodb
我有一个REST API,可以根据请求计算内容,如果再次发出相同的请求,请从缓存中返回结果,该缓存由保存在MongoDB中的文档组成。要知道两个请求是否相同,我对请求中的一些相关字段进行了哈希处理。但是当快速连续提出相同的请求时,MongoDB中会出现重复的文档,当我尝试读取它们时,稍后会导致“ IncorrectResultSizeDataAccessException”。
为解决这个问题,我尝试在以下控制器方法中同步哈希值(试图切掉不相关的部分):
@PostMapping(
path = "/{myPath}",consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE},produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
@Async("asyncExecutor")
public CompletableFuture<ResponseEntity<?>> retrieveAndCache( ... a,b,c,d various request parameters) {
//perform some validations on request...
//hash relevant equest parameters
int hash = Objects.hash(a,d);
synchronized (Integer.toString(hash).intern()) {
Optional<Result> resultOpt = cacheService.findByHash(hash);
if (resultOpt.isPresent()) {
return CompletableFuture.completedFuture(ResponseEntity.status(HttpStatus.OK).body(opt.get().getResult()));
} else {
Result result = ...//perform requests to external services and do some calculations...
cacheService.save(result);
return CompletableFuture.completedFuture(ResponseEntity.status(HttpStatus.OK).body(result));
}
}
}
//cacheService methods
@Transactional
public Optional<Result> findByHash(int hash) {
return repository.findByHash(hash); //this is the part that throws the error
}
我确定不会发生哈希冲突,只是在快速连续执行相同请求时才发生重复记录。据我了解,只要我的Spring Boot应用程序只有1个正在运行的实例,就不应发生这种情况。除了生产环境中正在运行多个实例之外,您是否还看到其他原因?
解决方法
您应检查MongoDB客户端的设置。
如果一个线程调用cacheService.save(result)
方法,并在该方法返回后释放锁,然后另一个线程调用cacheService.findByHash(hash)
,则仍然有可能找不到您刚刚保存的记录。
例如只要已保存的对象在事务日志中但尚未完全处理,save方法就会返回。或在主节点上处理保存,但是findByHash在尚未复制的辅助节点上执行。
您可以使用WriteConcern.MAJORITY,但我不确定100%是否涵盖所有内容。
更好的是让MongoDB通过将findAndModify
与FindAndModifyOptions.upsert(true)
一起使用来进行锁定,而忘记了Java代码中的锁定。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。