java 为什么@Cacheable在后续调用中返回不同的结果

ehxuflar  于 2023-05-12  发布在  Java
关注(0)|答案(1)|浏览(212)

Sping Boot 2.6.14版本

控制器

@PostMapping("/v1/books)
public GenericResponse<Book> getBooks(BookRequest request) {
  return new GenericResponse<>(
      loggedInBookService.findBooks(request)
  );
}

服务项目

@Cacheable("books")
public Page< Book> findBooks(BookRequest request) {
  return bookService(request);
}

申请

@Setter
@Getter
@AllArgsConstructor(access = PRIVATE)
@NoArgsConstructor(access = PRIVATE)
public class BookRequest implements Serializable {

  private String isbn;

  private List<String> isbns;

  private LocalDate bookAddedDateFrom;

  private LocalDate bookAddedDateTo;

  private boolean hasCopy = true;
}

我在第一个请求中将'hasCopy'设置为'true'时收到了正确的响应。然而,在随后的请求中,我收到了一个不正确的响应,表现得好像'hasCopy'被设置为'false'。
是什么导致了这个问题?

44u64gxh

44u64gxh1#

乍一看,我看到的@Cacheable注解的findBooks(:BookRequest)服务方法的直接问题是,BookRequest对象没有实现Objectequals(:Object)hashCode()方法。
有两件事你需要知道:
1.首先,Spring Framework的Cache Abstraction默认情况下使用@Cacheable注解方法的声明参数的参数作为该高速缓存条目的键,除非您通过使用key属性或自定义KeyGenerator另行指定。
在您的示例中,findBooks(..)服务方法该高速缓存条目为:

bookRequest: Page<Book>

1.其次,由于Cache只不过是一个(美化的)Map数据结构,因此equals(:Object)hashCode()方法的实现非常重要。
我没有看到您实际上在BookRequest对象上实现了equals(:Object)hashCode()方法。由于您使用的是Lombok,因此只需在BookRequest类上声明Lomboks的@EqualsAndHashCode注解即可实现equals(:Object)hashCode()
但是,equals(:Object)hashCode()方法必须为逻辑上相同的对象一致地返回相同的值。
假设你的BookRequest有一个ISBN,并且ISBN唯一地标识了Book,那么你可以通过以下操作来使用ISBN,而不是使用BookRequest作为该高速缓存条目中的“键”:

@Service
class BookService {

  @Cacheable(name = "Books", key="#bookRequest.isbn")
  public Page<Book> findBooks(BookRequest bookRequest) {
  }
}

同样,请参阅参考文档中关于自定义键以及在@Cacheable注解属性中使用SpEL的内容,如key,以了解更多详细信息。
如果您没有启用Java compiler debug mode,则需要将#bookRequest.isbn替换为#a0.isbn
即使BookRequest类上没有equals(:Object)hashCode()方法实现,在@Cacheable注解集上使用key属性BookRequestisbn应该足够了。但是,只有当ISBN始终存在于请求中时,这才有效(我怀疑可能不是)。
另外,无论如何,覆盖并实现Objectequals(:Object)hashCode()方法始终是一个好的做法。
祝你好运!

相关问题