#java #postgresql #hibernate #orm #hibernate-mapping
#java #postgresql #режим гибернации #orm #режим гибернации-сопоставление
Вопрос:
Я настроил тестовое приложение с использованием Hibernate, PostgreSQL и Spring, и я продолжаю сталкиваться с этой необъяснимой ошибкой. Я надеюсь, что кто-нибудь здесь может пролить некоторый свет на проблему.
Моя сущность выглядит следующим образом:
@Entity
@Table(name = "something")
public class Something {
@Id
@SequenceGenerator(name = "somethingGen", sequenceName = "something_id_seq", allocationSize = 30)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "somethingGen")
@Column(name = "id", unique = true, nullable = false)
private long id;
public Something() {
}
public long getId() {
return id;
}
@Override
public String toString() {
return new StringJoiner(", ", Something.class.getSimpleName() "[", "]")
.add("id=" id)
.toString();
}
}
В целях тестирования я создал хранилище данных Spring, вставил пять записей и извлек их обратно:
System.out.println("starting...");
for (int i = 0; i < 5; i ) {
repository.save(new Something());
}
repository.findAll().forEach(System.out::println);
В первый раз, когда я запускаю этот код, он работает почти так, как ожидалось:
Something[id=1]
Something[id=2]
Something[id=3]
Something[id=4]
Something[id=5]
Однако во второй раз я сталкиваюсь с этим исключением: org.hibernate.MappingException: The increment size of the [something_id_seq] sequence is set to [30] in the entity mapping while the associated database sequence increment size is [1].
Итак, я проверил последовательность в Postgres DB:
uat=# d something_id_seq
Sequence "public.something_id_seq"
Column | Type | Value
--------------- --------- ---------------------
sequence_name | name | something_id_seq
last_value | bigint | 1
start_value | bigint | 1
increment_by | bigint | 1
max_value | bigint | 9223372036854775807
min_value | bigint | 1
cache_value | bigint | 1
log_cnt | bigint | 32
is_cycled | boolean | f
is_called | boolean | t
Это первая проблема. Похоже, что Hibernate создает последовательности с неправильным значением приращения. Итак, я изменил значение increment_by: alter sequence something_id_seq increment 30
и снова запустил свой код, и в итоге получился такой результат:
Something[id=1]
Something[id=2]
Something[id=3]
Something[id=4]
Something[id=5]
Something[id=901]
Something[id=902]
Something[id=903]
Something[id=904]
Something[id=905]
И теперь последовательность выглядит следующим образом:
--------------- --------- ---------------------
sequence_name | name | something_id_seq
last_value | bigint | 31
start_value | bigint | 1
increment_by | bigint | 30
Итак, мне кажется, что новый идентификатор вычисляется через increment_by * allocation_size last_value
, но я ожидал, что новый идентификатор будет равен 30 ( allocation_size * last_value
), поскольку я подозревал, что это increment_by
и allocationSize
будет одно и то же из-за исключения MappingException .
Это оставляет меня с двумя вопросами:
-
Я ожидал, что идентификаторы будут около 0, 30, 60, 90… и вместо этого я получил идентификаторы около 1 и 900. Javadoc SequenceGenerator утверждает, что размер распределения равен
the amount to increment by when allocating sequence numbers from the sequence
. Означает ли это, чтоincrement_by
иallocationSize
это не одно и то же? Как они связаны друг с другом (например, почему я вижуMappingException
) и как мне добиться ожидаемого поведения? -
Исключение MappingException указывает мне, что Hibernate создает последовательности с неправильным значением приращения. Как мне заставить Hibernate создать правильный?
Я использую Hibernate 5.4.2.Final и PostgreSQL 9.6.12 и эти настройки:
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
hibernateJpaVendorAdapter.setDatabasePlatform(PostgreSQL9Dialect.class.getName());
hibernateJpaVendorAdapter.setGenerateDdl(true);
Я подозреваю, что проблема может быть где-то с генератором HiLo, но, хоть убейте, я не могу в этом разобраться:
hibernate.id.new_generator_mappings=true
hibernate.id.optimizer.pooled.preferred=hilo
hibernate.schema_update.unique_constraint_strategy=RECREATE_QUIETLY
Ответ №1:
increment_by
и allocationSize
должны быть того же размера. Однако, если у вас нет распределенной системы с большим количеством вставок, вам следует просто использовать значение по умолчанию, increment_by
равное 1, и использовать @GeneratedValue(strategy = GenerationType.IDENTITY)
.
Вероятно, в конечном итоге вы переходите к 900 из-за того, что различные потоки резервируют идентификатор, но затем не выполняют вставку. У меня была эта проблема. Теперь я вставляю с IDENTITY
.
Что касается исключения MappingException, something_id_seq
последовательность создается автоматически postgres, потому что диалект PostgreSQL использует serial
or bigserial
при создании таблицы. Смотрите PostgreSQL81IdentityColumnSupport. Возможно, следует считать ошибкой то, что Hibernate не изменяет последовательность на allocationSize
, и вы можете сообщить об этом.
Комментарии:
1. Я не использую никаких потоков. Приведенный выше пример кода на самом деле представляет собой весь код приложения. Я не думаю, что последовательность генерируется PostgreSQL, потому что оператор create регистрируется, и если я не использую HiLo, то приращение правильное.