30 июн. 2015 г.

Странный auto increment при работе с Hibernate и H2 database

При работе с фреймворком Hibernate и базой данных H2 можно наблюдать странную картину при назначении id записи в базе данных.
Например, может наблюдаться такая последовательность id-шников:
1  2  3  4  5  6  7  8  33  34  35  65 ...



Красным здесь отмечен каждый запуск приложения.
Получается, в первый запуск мы вставили записи: 1  2  3  4  5  6  7  8
второй запуск -  33  34  35
третий запуск -  65 ...

Такое ощущение, что мы вставляли подряд записи, а потом часть из них удалили. Но нет, записи не удалялись.

Покопавшись и перепробовав несколько баз данных (MySQL, HSQLBD, H2), я выяснил, что такое происходит только с базой H2. Если присмотреться к цифрам, то можно увидеть, что в  базе при каждой 32-й записи под индексы резервируется еще 32.
Мы  вставляем запись №1, зарезервировалось 32. Перезапускаем приложение, вставляем опять запись, 32 у нас уже как бы есть (были зарезервированы прошлый запуск), значит вставится запись под номером 33. И т.д.

Какая причина резервирования
Причина простая. В базе H2 по умолчанию стоит кеширование, размер кеша = 32 записи. Кеширование используется для предотвращения потери данных при падении базы (или неправильном завершении приложения).


Почитав форумы и разные ресурсы нашлось несколько решений проблемы с генерацией и резервированием.

Решение 1
Добавить вот такие аннотации к нашему полю id:
@Id @Column(name="...") 
@GeneratedValue(strategy=GenerationType.TABLE, generator="generatorName")
@TableGenerator(name="generatorName", allocationSize=1) 
private Long id;

generatorName - может быть любым. 
 
После этого должна быть нормальная последовательность при автоматической генерации id (без пропусков).


Решение 2
Использовать другую базу данных, не H2, где нет кеширования.
Решение 3 (неопробованное)
@Id
@GenericGenerator(name="kaugen" , strategy="increment")
@GeneratedValue(generator="kaugen")
@Column(name="proj_id")
private Long id;

Eclipse будет выдавать ошибку, которая решается так:
Вариант 1
или так
Вариант 2

Решение 4 (неопробованное)
Можно написать свой генератор для id (ссылка на ресурс в конце).


Решение 5 (неопробованное)
Можно найти как задать размер кеша для базы H2, сделать это и написать в комментарии к статье, как вы это сделали :)

Ресурс, откуда взяты примеры: 
Там же можно найти, как написать свой генератор.

3 комментария:

Спрашивайте, критикуйте, оставьте свое мнение