Скоро наступит 2013 год, но тем не менее в программировании есть еще люди, полагающиеся на уникальность хэшкода.
Spring Framework сильно удивил стратегией по умолчанию для генерации ключа в своей кэш-абстракции: в случае для метода с несколькими параметрами, в версии фреймворка 3.1 и 3.2 в качестве ключа выбирается общий хэш значений аргументов, аналогичный тому алгоритму, что используется в методе Objects.hash(Object… ) или Arrays.hashСode(Object[]) — в хэш функцию последовательно передаются значения аргументов метода.
К счастью или (несчастью) все это быстро всплыло, т.к. одно только магическое умножение не дает качественного разброса по значениям.
Алгоритм генерации ключа:
Народ уже столкнулся в продакшене с коллизией
и
Так и представляю, как при просмотре счета в какой нибудь распределенной системе типа «интернет-банк» (банки Spring любят) выведутся данные чужого счета.
Неясно, что мешало разработчикам Spring провести конкатенацию аргументов, или лучше документировать вопрос в руководстве. Но судя по примеру
можно сделать вывод, что они действительно верят в стратегию с хэшированием.
Хотя, по-моему все же лучшее решение — стараться не использовать несколько первичных ключей вообще.
Spring Framework сильно удивил стратегией по умолчанию для генерации ключа в своей кэш-абстракции: в случае для метода с несколькими параметрами, в версии фреймворка 3.1 и 3.2 в качестве ключа выбирается общий хэш значений аргументов, аналогичный тому алгоритму, что используется в методе Objects.hash(Object… ) или Arrays.hashСode(Object[]) — в хэш функцию последовательно передаются значения аргументов метода.
К счастью или (несчастью) все это быстро всплыло, т.к. одно только магическое умножение не дает качественного разброса по значениям.
Алгоритм генерации ключа:
public Object generate(Object target, Method method, Object... params) {
if (params.length == 1) {
return (params[0] == null ? NULL_PARAM_KEY : params[0]);
}
if (params.length == 0) {
return NO_PARAM_KEY;
}
int hashCode = 17;
for (Object object : params) {
hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode());
}
return Integer.valueOf(hashCode);
}
Народ уже столкнулся в продакшене с коллизией
new Integer( 109 ),new Integer( 434)
и
new Integer( 110 ),new Integer( 403)
Так и представляю, как при просмотре счета в какой нибудь распределенной системе типа «интернет-банк» (банки Spring любят) выведутся данные чужого счета.
Неясно, что мешало разработчикам Spring провести конкатенацию аргументов, или лучше документировать вопрос в руководстве. Но судя по примеру
@Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
можно сделать вывод, что они действительно верят в стратегию с хэшированием.
Хотя, по-моему все же лучшее решение — стараться не использовать несколько первичных ключей вообще.