使用亲和键(affinity key)并置时如何保留仅传ID的键值API能力
可行方案
有两种可落地的实现方式,都能同时满足数据并置性能要求、以及仅通过原始数据ID调用KV API的需求,不需要改造现有readthrough逻辑。
方案1:直接使用原始类型作为KV键(最简便)
不需要使用内置的AffinityKey包装类,直接用原始整数类型(Long/Integer等)作为缓存键,仅需在缓存对应的value实体类中,给用于并置的亲和键字段添加@AffinityKeyMapped注解即可。
示例代码:
// 缓存值实体类 public class Order { // 实体主键,对应KV调用时传入的原始ID private Long orderId; // 用于数据并置的亲和键(例如关联的用户ID),添加注解后Ignite会自动基于该字段计算分区位置 @AffinityKeyMapped private Long userId; // 其余业务字段、构造方法、getter/setter省略 }
使用时和普通KV操作完全一致,直接调用cache.get(orderId)即可正常触发readthrough逻辑,命中缓存。SQL查询时只要按userId字段做关联匹配,会自动享受数据并置的性能优势,不会产生跨节点分布式查询。
方案2:自定义键类,重写相等判断逻辑
如果需要保留键类封装,可以自定义键类型,不使用内置的AffinityKey:
- 键类中同时包含实体主键ID、亲和键两个字段
- 给亲和键字段添加
@AffinityKeyMapped注解,告诉Ignite基于该字段做分区并置 - 重写
equals()和hashCode()方法,仅基于实体主键ID做判断,不纳入亲和键字段
示例代码:
public class OrderKey { // 实体主键ID private Long orderId; // 数据并置用的亲和键 @AffinityKeyMapped private Long userId; // 构造方法、getter/setter省略 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; OrderKey that = (OrderKey) o; return Objects.equals(orderId, that.orderId); } @Override public int hashCode() { return Objects.hash(orderId); } }
这种方式下,即使构造OrderKey时只传入orderId、不填userId,也能正常命中缓存、触发readthrough。等readthrough从数据库加载到全量数据后,把完整的键(带userId)和值写回缓存即可,后续分区路由、SQL并置查询都能正常生效。
内置AffinityKey无法仅用ID匹配的原因
内置AffinityKey类本身的equals()和hashCode()逻辑是同时校验「实体ID」和「亲和键」两个字段的,和KeyCacheObject包装层没有关系。只传ID时,因为缺少亲和键字段值,相等判断必然不通过,自然无法命中缓存。
适配注意事项
- 使用上述两种方案时,readthrough逻辑不需要做特殊改造:如果用原始类型键,
CacheStore的load()方法接收到的参数就是你传入的原始ID,直接查库返回对应实体即可,只要保证返回的实体中@AffinityKeyMapped标记的字段值正确,Ignite会自动完成分区路由。 - 不要尝试修改内置
AffinityKey的相等判断逻辑,会破坏Ignite内部的分区校验规则,可能导致数据路由错误。
内容的提问来源于stack exchange,提问作者ofer.ignite
相关产品推荐
相关产品推荐

