Как стать автором
Обновить

Хэш коллизии в кэш-абстракции Spring для методов с несколькими аргументами

Скоро наступит 2013 год, но тем не менее в программировании есть еще люди, полагающиеся на уникальность хэшкода.

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)

можно сделать вывод, что они действительно верят в стратегию с хэшированием.

Хотя, по-моему все же лучшее решение — стараться не использовать несколько первичных ключей вообще.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.