Все мы знаем поведение Hibernate по умолчанию при использовании @SequenceGenerator
- он увеличивает реальную последовательность базы данных на единицу , умножает это значение на 50 (значение по умолчанию allocationSize
), а затем использует это значение в качестве идентификатора объекта.
Это неправильное поведение и противоречит спецификации, которая гласит:
allocationSize - (Необязательно) Сумма увеличения при выделении порядковых номеров из последовательности.
Для ясности: меня не беспокоят пробелы между сгенерированными идентификаторами.
Меня интересуют идентификаторы, которые не соответствуют базовой последовательности базы данных. Например: любое другое приложение (например, использующее простой JDBC) может захотеть вставить новые строки под идентификаторами, полученными из последовательности, но все эти значения могут уже использоваться Hibernate! Безумие.
Кто-нибудь знает какое-либо решение этой проблемы (без настройки allocationSize=1
и, следовательно, снижения производительности)?
РЕДАКТИРОВАТЬ:
чтобы прояснить ситуацию. Если последняя вставленная запись имела ID = 1
, тогда HB использует значения 51, 52, 53...
для своих новых сущностей, НО в то же время: значение последовательности в базе данных будет установлено на 2
. Что может легко привести к ошибкам, когда другие приложения используют эту последовательность.
С другой стороны: в спецификации говорится (в моем понимании), что последовательность базы данных должна быть установлена, 51
а в то же время HB должен использовать значения из диапазона 2, 3 ... 50
ОБНОВЛЕНИЕ:
Как упомянул ниже Стив Эберсол: описанное мной поведение (а также наиболее интуитивное для многих) можно включить, установив hibernate.id.new_generator_mappings=true
.
Спасибо всем вам.
ОБНОВЛЕНИЕ 2:
Для будущих читателей ниже вы можете найти рабочий пример.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ")
@SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS")
private Long id;
}
persistence.xml
<persistence-unit name="testPU">
<properties>
<property name="hibernate.id.new_generator_mappings" value="true" />
</properties>
</persistence-unit>
save
нужно запросить базу данных для следующего значения последовательности.SequenceGenerator
Hibernate будет запрашивать базу данных только тогда, когда количество идентификаторов, указанных в,allocationsize
заканчивается. Если вы настроили,allocationSize = 1
то это причина, по которой Hibernate запрашивает БД для каждой вставки. Измените это значение, и все готово.hibernate.id.new_generator_mappings
установка действительно важно. Я надеюсь, что это настройка по умолчанию, и мне не придется тратить так много времени на изучение того, почему идентификационный номер сходит с ума.Ответы:
Чтобы быть абсолютно ясным ... то, что вы описываете, никоим образом не противоречит спецификации. В спецификации говорится о значениях, которые Hibernate присваивает вашим объектам, а не о значениях, фактически хранящихся в последовательности базы данных.
Однако есть возможность получить желаемое поведение. Сначала см. Мой ответ на тему. Есть ли способ динамически выбирать стратегию @GeneratedValue с использованием аннотаций JPA и Hibernate? Это даст вам основы. Пока вы настроены на использование этого SequenceStyleGenerator, Hibernate будет интерпретировать,
allocationSize
используя «объединенный оптимизатор» в SequenceStyleGenerator. «Объединенный оптимизатор» предназначен для использования с базами данных, которые позволяют использовать параметр «приращение» при создании последовательностей (не все базы данных, поддерживающие последовательности, поддерживают приращение). В любом случае, прочтите там о различных стратегиях оптимизатора.источник
org.hibernate.id.enhanced.SequenceStyleGenerator
. Вы меня удивили.allocationSize=1
Это микрооптимизация перед получением запроса. Hibernate пытается присвоить значение в диапазоне allocationSize и поэтому старается избегать запросов к базе данных для определения последовательности. Но этот запрос будет выполняться каждый раз, если вы установите для него значение 1. Это вряд ли имеет какое-либо значение, поскольку, если к вашей базе данных обращается какое-то другое приложение, это создаст проблемы, если тот же идентификатор будет использоваться другим приложением.Следующее поколение Sequence Id основано на allocationSize.
По умолчанию это
50
слишком много. Это также поможет, только если вы собираетесь50
записей в одном сеансе, которые не сохраняются и которые будут сохраняться с использованием этого конкретного сеанса и передачи.Таким образом , вы всегда должны использовать во
allocationSize=1
время использованияSequenceGenerator
. Как и для большинства базовых баз данных, последовательность всегда увеличивается на1
.источник
allocationSize=1
Hibernate при каждойsave
операции необходимо совершать переход к базе данных, чтобы получить новое значение идентификатора.allocationSize
поэтому старайтесь избегать запросов к базе данных для последовательности. Но этот запрос будет выполняться каждый раз, если вы установите его на 1. Это вряд ли имеет какое-либо значение, поскольку если к вашей базе данных обращается какое-то другое приложение, это создаст проблемы, если тот же идентификатор будет использоваться другим приложением,Стив Эберсол и другие участники, не
могли бы вы объяснить причину появления идентификатора с большим пробелом (по умолчанию 50)? Я использую Hibernate 4.2.15 и обнаружил следующий код в org.hibernate.id.enhanced.OptimizerFactory cass.
Каждый раз, когда он попадает внутрь оператора if, значение hi становится намного больше. Итак, мой id во время тестирования с частым перезапуском сервера генерирует следующие идентификаторы последовательности:
1, 2, 3, 4, 19, 250, 251, 252, 400, 550, 750, 751, 752, 850, 1100, 1150.
Я знаю, что вы уже сказали, что это не противоречит спецификации, но я считаю, что это будет очень неожиданная ситуация для большинства разработчиков.
Любой вклад будет очень полезным.
Jihwan
ОБНОВЛЕНИЕ: ne1410s: Спасибо за редактирование.
cfrick: Хорошо. Я сделаю это. Это был мой первый пост здесь, и я не знал, как его использовать.
Теперь я лучше понял, почему maxLo использовался для двух целей: поскольку спящий режим вызывает последовательность БД один раз, продолжает увеличивать идентификатор на уровне Java и сохраняет его в БД, значение идентификатора уровня Java должно учитывать, сколько было изменено без вызова последовательность DB, когда она вызывает последовательность в следующий раз.
Например, в какой-то момент идентификатор последовательности был равен 1, а в режиме гибернации введено значение 5, 6, 7, 8, 9 (с allocationSize = 5). В следующий раз, когда мы получим следующий порядковый номер, DB вернет 2, но для гибернации необходимо использовать 10, 11, 12 ... Вот почему "hi = lastSourceValue.copy (). MultiplyBy (maxLo + 1)" - это используется для получения следующего идентификатора 10 из 2, возвращенных из последовательности БД. Единственное, что беспокоило меня, это частый перезапуск сервера, и это была моя проблема с большим разрывом.
Итак, когда мы используем SEQUENCE ID, вставленный идентификатор в таблицу не будет совпадать с номером SEQUENCE в БД.
источник
После копания в исходном коде гибернации и конфигурации ниже переходит в Oracle db для получения следующего значения после 50 вставок. Так что увеличивайте INST_PK_SEQ на 50 каждый раз, когда он вызывается.
Hibernate 5 используется для стратегии ниже
Также проверьте ниже http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html#identifiers-generators-sequence
источник
allocationSize
ниinitialValue
глобально для всех сущностей (если не используете только один генератор, но ИМХО это не очень читается).Я тоже столкнулся с этой проблемой в Hibernate 5:
Получил предупреждение, подобное приведенному ниже:
Затем изменил мой код на SequenceStyleGenerator:
Это решило мои две проблемы:
источник
Я бы проверил DDL на предмет последовательности в схеме. Реализация JPA отвечает только за создание последовательности с правильным размером выделения. Следовательно, если размер выделения равен 50, тогда ваша последовательность должна иметь приращение 50 в своем DDL.
Этот случай обычно может происходить при создании последовательности с размером выделения 1, а затем сконфигурированной для размера выделения 50 (или по умолчанию), но DDL последовательности не обновляется.
источник
ALTER SEQUENCE ... INCREMENTY BY 50;
ничего не решит, потому что проблема осталась прежней. Значение последовательности по-прежнему не отражает идентификаторы реальных сущностей.