Генераторы идентификаторов JPA
JPA определяет следующие стратегии идентификаторов:
стратегия | Описание |
---|---|
АВТО | Поставщик персистентности выбирает наиболее подходящую стратегию идентификатора, поддерживаемую базовой базой данных. |
ИДЕНТИЧНОСТЬ | Идентификаторы назначаются столбцом IDENTITY базы данных. |
ПОСЛЕДОВАТЕЛЬНОСТЬ | Поставщик постоянства использует последовательность базы данных для генерации идентификаторов. |
СТОЛ | Поставщик сохраняемости использует отдельную таблицу базы данных для эмуляции объекта последовательности |
В моем предыдущем посте я рассмотрел плюсы и минусы всех этих стратегий суррогатного идентификатора.
Идентификатор оптимизаторов
Хотя оптимизации генератора IDENTITY на стороне приложения не так много (кроме настройки предварительного распределения идентификаторов базы данных), идентификаторы последовательности предлагают гораздо большую гибкость в этом отношении. Одна из наиболее распространенных стратегий оптимизации основана на алгоритме распределения hi / lo .
Для этого Hibernate предлагает:
Генератор | Описание |
---|---|
SequenceHiLoGenerator | Он использует последовательность базы данных для генерации значения hi, в то время как нижнее значение увеличивается в соответствии с алгоритмом hi / lo |
TableHiLoGenerator |
Таблица базы данных используется для генерации значений hi. Этот генератор не рекомендуется в пользу MultipleHiLoPerTableGenerator, расширенного TableGenerator или SequenceStyleGenerator. |
MultipleHiLo PerTableGenerator |
Это генератор таблиц hi / lo, способный использовать одну таблицу базы данных даже для нескольких последовательностей идентификаторов. |
SequenceStyleGenerator | Это расширенная версия предыдущего генератора последовательности. Он использует последовательность, если базовая база данных поддерживает их. Если текущая база данных не поддерживает последовательности, она переключается на использование таблицы для генерации значений последовательности. В то время как предыдущие генераторы имели предопределенный алгоритм оптимизации, расширенные генераторы можно настроить с помощью стратегии оптимизатора:
Пул является стратегией оптимизатора по умолчанию. |
TableGenerator | Как и MultipleHiLoPerTableGenerator, он может использовать одну таблицу для нескольких генераторов идентификаторов, предлагая настраиваемые стратегии оптимизатора.
Пул является стратегией оптимизатора по умолчанию. |
Отображение идентификатора JPA в Hibernate
Имея такое обширное предложение генераторов, мы не можем не спросить, какой из них используется в качестве генераторов JPA по умолчанию.
Хотя спецификация JPA не предполагает какой-либо конкретной оптимизации, Hibernate предпочтет оптимизированный генератор, а не тот, который всегда попадает в базу данных для каждого нового идентификатора.
JPA SequenceGenerator
Мы определим один объект, настроенный с помощью генератора идентификаторов SEQUENCE JPA. В модульном тесте будет сохраняться пять таких объектов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Entity (name = "sequenceIdentifier" ) public static class SequenceIdentifier { @Id @GeneratedValue (generator = "sequence" , strategy=GenerationType.SEQUENCE) @SequenceGenerator (name = "sequence" , allocationSize = 10 ) private Long id; } @Test public void testSequenceIdentifierGenerator() { LOGGER.debug( "testSequenceIdentifierGenerator" ); doInTransaction( new TransactionCallable<Void>() { @Override public Void execute(Session session) { for ( int i = 0 ; i < 5 ; i++) { session.persist( new SequenceIdentifier()); } session.flush(); return null ; } }); } |
Запустив этот тест, мы получим следующий вывод
01
02
03
04
05
06
07
08
09
10
11
|
Query:{[call next value for hibernate_sequence][]} Generated identifier: 10, using strategy: org.hibernate. id .SequenceHiLoGenerator Generated identifier: 11, using strategy: org.hibernate. id .SequenceHiLoGenerator Generated identifier: 12, using strategy: org.hibernate. id .SequenceHiLoGenerator Generated identifier: 13, using strategy: org.hibernate. id .SequenceHiLoGenerator Generated identifier: 14, using strategy: org.hibernate. id .SequenceHiLoGenerator Query:{[insert into sequenceIdentifier ( id ) values (?)][10]} Query:{[insert into sequenceIdentifier ( id ) values (?)][11]} Query:{[insert into sequenceIdentifier ( id ) values (?)][12]} Query:{[insert into sequenceIdentifier ( id ) values (?)][13]} Query:{[insert into sequenceIdentifier ( id ) values (?)][14]} |
Hibernate выбирает использовать устаревший SequenceHiLoGenerator для обратной совместимости со всеми приложениями, которые были разработаны до выпуска усовершенствованных генераторов. Перенос унаследованного приложения на новые генераторы — непростой процесс, поэтому улучшенные генераторы — лучшая альтернатива для новых приложений.
Hibernate предпочитает использовать генератор «seqhilo» по умолчанию, что не является интуитивным предположением, поскольку многие могут ожидать необработанный генератор «sequence» (всегда вызывая последовательность базы данных для каждого нового значения идентификатора).
Чтобы включить расширенные генераторы, нам нужно установить следующее свойство Hibernate:
1
|
properties.put( "hibernate.id.new_generator_mappings" , "true" ); |
Дает нам следующий вывод:
01
02
03
04
05
06
07
08
09
10
11
12
|
Query:{[call next value for hibernate_sequence][]} Query:{[call next value for hibernate_sequence][]} Generated identifier: 1, using strategy: org.hibernate. id .enhanced.SequenceStyleGenerator Generated identifier: 2, using strategy: org.hibernate. id .enhanced.SequenceStyleGenerator Generated identifier: 3, using strategy: org.hibernate. id .enhanced.SequenceStyleGenerator Generated identifier: 4, using strategy: org.hibernate. id .enhanced.SequenceStyleGenerator Generated identifier: 5, using strategy: org.hibernate. id .enhanced.SequenceStyleGenerator Query:{[insert into sequenceIdentifier ( id ) values (?)][1]} Query:{[insert into sequenceIdentifier ( id ) values (?)][2]} Query:{[insert into sequenceIdentifier ( id ) values (?)][3]} Query:{[insert into sequenceIdentifier ( id ) values (?)][4]} Query:{[insert into sequenceIdentifier ( id ) values (?)][5]} |
Новый SequenceStyleGenerator генерирует другие значения идентификатора, чем унаследованный SequenceHiLoGenerator. Причина, по которой операторы обновления различаются между старым и новым генераторами, заключается в том, что стратегия оптимизатора по умолчанию для новых генераторов «объединена», в то время как старые генераторы могут использовать только стратегию «hi / lo».
JPA TableGenerator
1
2
3
4
5
6
7
8
|
@Entity (name = "tableIdentifier" ) public static class TableSequenceIdentifier { @Id @GeneratedValue (generator = "table" , strategy=GenerationType.TABLE) @TableGenerator (name = "table" , allocationSize = 10 ) private Long id; } |
Выполнение следующего теста:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Test public void testTableSequenceIdentifierGenerator() { LOGGER.debug( "testTableSequenceIdentifierGenerator" ); doInTransaction( new TransactionCallable<Void>() { @Override public Void execute(Session session) { for ( int i = 0 ; i < 5 ; i++) { session.persist( new TableSequenceIdentifier()); } session.flush(); return null ; } }); } |
Создает следующий вывод оператора SQL:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
Query:{[ select sequence_next_hi_value from hibernate_sequences where sequence_name = 'tableIdentifier' for update][]} Query:{[insert into hibernate_sequences(sequence_name, sequence_next_hi_value) values( 'tableIdentifier' , ?)][0]} Query:{[update hibernate_sequences set sequence_next_hi_value = ? where sequence_next_hi_value = ? and sequence_name = 'tableIdentifier' ][1,0]} Generated identifier: 1, using strategy: org.hibernate. id .MultipleHiLoPerTableGenerator Generated identifier: 2, using strategy: org.hibernate. id .MultipleHiLoPerTableGenerator Generated identifier: 3, using strategy: org.hibernate. id .MultipleHiLoPerTableGenerator Generated identifier: 4, using strategy: org.hibernate. id .MultipleHiLoPerTableGenerator Generated identifier: 5, using strategy: org.hibernate. id .MultipleHiLoPerTableGenerator Query:{[insert into tableIdentifier ( id ) values (?)][1]} Query:{[insert into tableIdentifier ( id ) values (?)][2]} Query:{[insert into tableIdentifier ( id ) values (?)][3]} Query:{[insert into tableIdentifier ( id ) values (?)][4]} Query:{[insert into tableIdentifier ( id ) values (?)][5]} |
Как и в предыдущем примере SEQUENCE, Hibernate использует MultipleHiLoPerTableGenerator для обеспечения обратной совместимости.
Переключение на расширенные генераторы идентификаторов:
1
|
properties.put( "hibernate.id.new_generator_mappings" , "true" ); |
Дайте нам следующий вывод:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
Query:{[ select tbl.next_val from hibernate_sequences tbl where tbl.sequence_name=? for update][tableIdentifier]} Query:{[insert into hibernate_sequences (sequence_name, next_val) values (?,?)][tableIdentifier,1]} Query:{[update hibernate_sequences set next_val=? where next_val=? and sequence_name=?][11,1,tableIdentifier]} Query:{[ select tbl.next_val from hibernate_sequences tbl where tbl.sequence_name=? for update][tableIdentifier]} Query:{[update hibernate_sequences set next_val=? where next_val=? and sequence_name=?][21,11,tableIdentifier]} Generated identifier: 1, using strategy: org.hibernate. id .enhanced.TableGenerator Generated identifier: 2, using strategy: org.hibernate. id .enhanced.TableGenerator Generated identifier: 3, using strategy: org.hibernate. id .enhanced.TableGenerator Generated identifier: 4, using strategy: org.hibernate. id .enhanced.TableGenerator Generated identifier: 5, using strategy: org.hibernate. id .enhanced.TableGenerator Query:{[insert into tableIdentifier ( id ) values (?)][1]} Query:{[insert into tableIdentifier ( id ) values (?)][2]} Query:{[insert into tableIdentifier ( id ) values (?)][3]} Query:{[insert into tableIdentifier ( id ) values (?)][4]} Query:{[insert into tableIdentifier ( id ) values (?)][5]} |
Вы можете видеть, что на этот раз был использован новый улучшенный TableGenerator .
Подробнее об этих стратегиях оптимизации вы можете прочитать в оригинальной заметке о выпуске .
- Код доступен на GitHub .
Ссылка: | От JPA до устаревших генераторов идентификаторов Hibernate от нашего партнера JCG Влада Михалча в блоге Влада Михалча . |