Hibernate и странное поведение с последовательностями DB2 - PullRequest
1 голос
/ 11 февраля 2010

Я использую Hibernate с Spring и DB2. Я использую последовательности для генерации первичного ключа для сущностей. Все объекты используют одинаковую последовательность HIBERNATE_SEQUENCE, которая является спящим по умолчанию.

Проблема в том, что значения, которые заканчиваются первичными ключами, примерно в 10 раз превышают значения, возвращаемые HIBERNATE_SEQUENCE.

Например, эта ситуация сразу после вставки новой строки в таблицу:

select max(id) as primary_key, nextval for hibernate_sequence sequence_value from tbl ;

primary_key sequence_value
501483661   50148373

Я сопоставил первичный ключ, как этот, в суперклассе для всех сущностей:

@MappedSuperclass
public class AbstractEntity implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE)
   private Integer id;

Я бы хотел, чтобы hibernate использовал те значения, которые он выбирает из последовательности, а не значения последовательности, умноженные на 10. Какой правильный способ сделать это?

Ответы [ 3 ]

2 голосов
/ 15 февраля 2010

Hibernate, кажется, делает следующее:

Когда hibernate нужен первичный ключ, он извлекает значение из последовательности. Hibernate сгенерирует несколько значений первичного ключа из значений одной последовательности. Например, hibernate будет хранить внутренний счетчик, значение которого добавляется к значению последовательности для получения значения первичного ключа. Когда внутренний счетчик достигает своего предела, счетчик сбрасывается, получается новое значение из последовательности и процесс первичного ключа начинается заново.

Например:

  1. Значение, полученное из sequece, равно 123. Полученное значение последовательности сохраняется за сеанс.
  2. Для текущего сеанса сгенерированные первичные ключи: 1230, 1231, 1232, 1233, ..., 1238, 1239. Значение счетчика объединяется со значением последовательности, полученным на шаге 1. При необходимости генерируется ключ.
  3. Теперь процесс генерации первичного ключа начинается заново. Перейти к 1.

Это вызывает следующие эффекты:

  • значение последовательности базы данных эффективно умножается на 10
  • Hibernate не обязан выполнять чтение базы данных для каждой вставки в БД, которую он делает. Приведенный выше алгоритм сокращает количество считываний последовательностей до 10% (при выполнении большого количества вставок в одном сеансе).
  • каждое другое не-спящее приложение должно использовать аналогичный алгоритм для генерации первичных ключей из последовательности, иначе в какой-то момент будут конфликты первичных ключей

Чтобы использовать в спящем режиме фактические значения, полученные из последовательности, можно использовать это отображение:

@Id
@GeneratedValue(generator="hibernate_sequence")
@GenericGenerator(strategy="sequence", name="hibernate_sequence")
private Integer id;
0 голосов
/ 29 мая 2014

Я решил эту проблему, установив allocationSize в 1 в @SequenceGenerator аннотации.

Пример:

@MappedSuperclass
public class AbstractEntity implements Serializable {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GENERATOR")
   private Integer id;

и субъект:

@SequenceGenerator(name = "SEQ_GENERATOR", sequenceName = "MY_SEQUENCE", allocationSize = 1)
public class MyEntity extends AbstractEntity {
0 голосов
/ 11 февраля 2010

Существует несколько параметров команды создания последовательности DB2, которые могут повлиять на это. INCREMENT_BY говорит, насколько увеличить значение при каждом вызове nextval. CACHE с NO_ORDER резервирует определенное количество значений, поэтому, если несколько соединений используют одну и ту же последовательность, они могут получить значения быстрее за счет того, что значения не в порядке. Я бы проверил, как сначала была создана последовательность, прежде чем копаться в Hibernate. Посмотрев на код Hibernate, он довольно прост - посмотрите на DB2Dialect, и вы увидите SQL, который он использует для получения значения последовательности.

...