Как increment_by последовательности PostgreSQL работает с allocSize Hibernate? - PullRequest
1 голос
/ 28 марта 2019

Я установил тестовое приложение с 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:

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.

Это оставляет меня с двумя вопросами:

  1. Я ожидал идентификаторы около 0, 30, 60, 90 ... и вместо этого я получил идентификаторы около 1 и 900Javadoc SequenceGenerator утверждает, что allocSize равен the amount to increment by when allocating sequence numbers from the sequence.Значит ли это, что increment_by и allocationSize не одно и то же?Как они связаны друг с другом (например, почему я вижу MappingException) и как мне добиться ожидаемого поведения?

  2. Исключение Mapping указывает мне, что 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 Ответ

0 голосов
/ 28 марта 2019

increment_by и allocationSize должны быть одинакового размера. Тем не менее, если у вас нет распределенной системы с высокой вставкой, вы должны просто использовать значение по умолчанию increment_by из 1 и использовать @GeneratedValue(strategy = GenerationType.IDENTITY).

Вы, вероятно, в конечном итоге переходите к 900 из-за того, что различные потоки зарезервировали идентификатор, но затем не смогли выполнить вставку. У меня была эта проблема. Теперь я вставляю с IDENTITY.

Что касается MappingException, последовательность something_id_seq создается автоматически postgres, потому что диалект PostgreSQL использует serial или bigserial при создании таблицы. См. PostgreSQL81IdentityColumnSupport . Возможно, следует учитывать, что Hibernate не изменяет последовательность на allocationSize, и вы можете сообщить об этом.

...