Apache Ignite存储含集合对象时查询结果不一致问题咨询
问题根因
- Ignite分区模式下备份数为1时,每份数据会同时存储在1个主分区节点和1个备份分区节点。默认情况下
SqlQuery会在所有持有该缓存数据的节点(含备份节点)执行查询,同一份数据会从主、备节点各返回一次。 - 你定义的
PersonImpl类没有重写equals()和hashCode()方法,默认使用JDK的引用相等判断。当类包含HashMap、ArrayList这类可变集合属性时,主、备节点返回的同一份数据反序列化后是不同的对象实例,引用不相等就不会被自动去重,最终出现重复数据。移除集合属性后如果剩下的都是不可变基础类型/包装类型,刚好满足值相等判断逻辑,就不会出现重复。 - 备份数调整为0后,所有数据仅存于主分区节点,查询时只会返回一次,自然不会有重复问题。
解决方案
- 方案1:显式指定查询不读取备份数据
构建SqlQuery时添加setIncludeBackups(false)配置,仅从主分区节点拉取数据,从源头上避免重复数据返回,修改后的查询代码如下:
这里额外补充了public <V> List<V> sqlQuery(Class<V> persistentClass, String t){ SqlQuery<K,V> sqlQuery = new SqlQuery<>(persistentClass,t); // 新增配置,不查询备份分区 sqlQuery.setIncludeBackups(false); List<V> values = new ArrayList<>(); try(QueryCursor<Entry<K,V>> queryCursor= getCache.query(sqlQuery)){ for(Entry<K,V> entry : queryCursor){ values.add(entry.getValue()); } } return values; }QueryCursor的资源关闭逻辑,避免资源泄漏。 - 方案2:重写实体类的
equals()和hashCode()方法
将所有业务上判断相等的属性都纳入方法计算逻辑,HashMap和ArrayList本身已经实现了基于内容的相等判断,直接调用即可,示例代码如下:
重写完成后,查询结果可以通过import java.util.Objects; public class PersonImpl{ private String name; private HashMap<Integer,String> attr = new HashMap<>(); private HashMap<Integer,String> attr1 = new HashMap<>(); private ArrayList<Integer> a; private ArrayList<Integer> b; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PersonImpl that = (PersonImpl) o; return Objects.equals(name, that.name) && Objects.equals(attr, that.attr) && Objects.equals(attr1, that.attr1) && Objects.equals(a, that.a) && Objects.equals(b, that.b); } @Override public int hashCode() { return Objects.hash(name, attr, attr1, a, b); } }values.stream().distinct().collect(Collectors.toList())手动去重,也能解决重复问题。
内容的提问来源于stack exchange,提问作者Krishna
相关产品推荐
相关产品推荐

