Map的HashCode做缓存key值引发的重大bug
现象:
计费和账户的交互通过Map来交互,基本数据格式如下{"pp900_88",20,"pp900_61",2……}
在不同的取值情况下,较多数据返回了相同的价格结果,导致计算价格错误。
?
应用场景:
产品计算价格时,使用cache缓存了价格结果数据,cache的key值是传入map的hashCode,本意是要实现完全相同的Map传入值从缓存取数据,减少数据库的访问。
?
?
原因分析:
?
一。通过如下代码模拟线上应用:
public final int hashCode() { return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); }?
以? m1.put("pp900_88", 1);? m1.put("pp900_61", 1);和
???? m1.put("pp900_88", 2);? m1.put("pp900_61", 2);为例子:得到的key-Value的hashCode值如下
?
key?????????????????? key的hashCode???value的hashCode? Map的hashCode(key^value)
??pp900_88??????? -79859962???????????? 1???????????????????? ? -79859961
??pp900_61????????-79860031???????????? 1?????????????????????? -79860032??pp900_88????????-79859962???????????? 2?????????????????????? -79859964??pp900_61????????-79860031 ??????????? 2???????????????????????-79860029?显然根据Map的hash值算法, Map的hashCode相加:第一行+第二行=第三行+第四行,这样产生重复数据也在所难免了,因为hashCode本来就不保证不同的输入值不会产生相同的结果。JSL的约束是对于相同的对象,必须产生相同的hashCode。结论和改进措施:1.不建议对结果进行缓存,结果缓存会带来很多问题,比如哪些数据变更需要刷新哪些缓存,缓存最好对原始纪录值进行缓存。2.key值不采用hashCode算法,直接改为使用各个key-value的String拼接字符串。??