Спящая последовательность оракула дает большой разрыв

Я использую Hibernate 3, оракул 10 г. У меня есть таблица: тема. Определение здесь

CREATE TABLE SUBJECT
    ( 
     SUBJECT_ID NUMBER (10), 
     FNAME VARCHAR2(30)  not null, 
     LNAME VARCHAR2(30)  not null, 
     EMAILADR VARCHAR2 (40),
     BIRTHDT  DATE       not null,
     constraint pk_sub primary key(subject_id) USING INDEX TABLESPACE data_index
    ) 
;

при вставке новой темы sub_seq используется для создания идентификатора субъекта, определение здесь

create sequence sub_seq
       MINVALUE 1 
       MAXVALUE 999999999999999999999999999 
       START WITH 1
       INCREMENT BY 1 
       CACHE 100 
       NOCYCLE ;

Предметный класс выглядит так:

@Entity
@Table(name="ktbs.syn_subject")
public class Subject {

    @Id 
    @Column(name="subject_id")
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ")
    @SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ")
    private long subjectId;
    private String fname;
    private String lname;
    private String emailadr;
    private Date birthdt;
}

в таблице тем было 4555 объектов в базе данных, загруженных сценариями plsql из Excel, и подпоследовательность работала нормально. субъекты в диапазоне от 1 до 4555

однако, когда я добавил тему из своего приложения, используя hibernate, порядковый номер перепрыгнул на 255050. После нескольких дней работы идентификаторы субъектов, сгенерированные hibernate, выглядят так

270079
270078
270077
270076
270075
270074
270073
270072
270071
270070
270069
270068
270067
270066
270065
270064
270063
270062
270061
270060
270059
270058
270057
270056
270055
270054
270053
270052
270051
270050
265057
265056
265055
265054
265053
265052
265051
265050
260059
260058
260057
260056
260055
260054
260053
260052
260051
260050
255067
255066
255065
255064
255063
255062
255061
255060
255059
255058
255057
255056
255055
255054
255053
255052
255051
255050
4555
4554
4553
.
.
.
.
1

Есть несколько больших пробелов: от 4555 до 255051, от 255067 до 260051, от 265057 до 270051

это пустая трата, а не желаемое поведение.

Кто-нибудь знает, почему это происходит, и горячо, чтобы это исправить

Спасибо

9 ответов

Решение

Я думаю, что проблема связана с тем фактом, что генератор последовательности на самом деле не является генератором последовательности, а генератором hilo последовательности с размером выделения по умолчанию 50. Как указано в документации: http://docs.jboss.org/ спящий режим / стабильный / аннотаций / ссылка / ен /html_single/# сущность-отображение-идентификатор

Это означает, что если значение последовательности равно 5000, следующее сгенерированное значение будет 5000 * 50 = 250000. Добавьте значение кэша последовательности в уравнение, и это может объяснить ваш огромный начальный разрыв.

Проверьте значение последовательности. Он должен быть меньше последнего сгенерированного идентификатора. Будьте осторожны, чтобы не инициализировать последовательность до этого последнего сгенерированного значения + 1, потому что сгенерированное значение будет расти экспоненциально (у нас была эта проблема, и у нас были отрицательные целочисленные идентификаторы из-за переполнения)

Согласитесь с JB. Но все же благодаря PaulJ.

Чтобы быть более конкретным для моего кода аннотации ниже:

@Entity
@Table(name="ktbs.syn_subject")
public class Subject {

  @Id 
  @Column(name="subject_id")
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ")
  @javax.persistence.SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ")
  private long subjectId;
  private String fname;
  private String lname;
  private String emailadr;
  private Date birthdt;
}

Если вы используете javax.persistence.SequenceGenerator, hibernate использовать hilo и, возможно, создаст большие пробелы в последовательности. Существует сообщение, посвященное этой проблеме: https://forum.hibernate.org/viewtopic.php?t=973682

Есть два способа решить эту проблему

  1. В аннотации SequenceGenerator добавьте allocationSize = 1, initialValue= 1
  2. вместо использования javax.persistence.SequenceGenerator используйте org.hibernate.annotations, например так:

    @javax.persistence.SequenceGenerator(
        name = "Question_id_sequence", 
        sequenceName = "S_QUESTION"
    )
    
    @org.hibernate.annotations.GenericGenerator(
        name="Question_id_sequence", 
        strategy = "sequence", 
        parameters = { 
            @Parameter(name="sequence", value="S_QUESTION") 
        }
    )
    

Я проверил оба способа, который работает просто отлично.

На самом деле, если вы используете sequenceSize=1, то это нормально. INCREMENT VALUE равен 1, и вам не нужно сохранять много сущностей. Однако, если вы хотите сохранить тысячи или миллионы записей, вышеуказанная настройка может стать узким местом для производительности, поскольку при каждом сохранении необходимо извлекать идентификатор, следовательно, требуется чтение из БД.

Чтобы решить эту проблему, нам нужно установить allocationSize к чему-то вроде 500 и последовательности INCREMENT VALUE в БД тоже до 500, потом самое главное добавить настройку гибернации hibernate.id.new_generator_mappings чтобы попросить его использовать новую реализацию генератора последовательностей, здесь я предполагаю, что вы устанавливаете свойства hibernate в классе java Config:

properties.setProperty("hibernate.id.new_generator_mappings", Boolean.toString(true));

Таким образом, Hibernate будет использовать SequenceStyleGenerator а не старый SequenceHiLoGenerator генерировать идентификаторы. SequenceStyleGenerator более jpa и oracle friendly. Он генерирует значения идентификаторов на основе структуры базы данных в стиле последовательности. Вариации варьируются от фактического использования последовательности до использования таблицы для имитации последовательности.

Посмотрите на мой пост более подробно, если вы находитесь в одной лодке:

vcfvct.wordpress.com/2016/04/23/jpa-sequencegenerator-with-allocationsize-1-performance-tuning/

Если вы прочитаете следующую ссылку, вы увидите, что проблема вызвана настройкой CACHE в вашей команде создания последовательности. Удаление настроек кеша до некоторой степени решит проблему, но не учитывает возможность откатов и т. Д.

Ссылка: http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:369390500346406705

Единственный способ выполнить повторную синхронизацию ваших последовательностей теперь состоит в том, чтобы заново создать последовательность, переименовать текущую таблицу и снова создать таблицу, а затем повторно вставить записи из старой таблицы в новую таблицу.

ПРИМЕЧАНИЕ. Значение кэша для последовательностей полезно для больших нагрузок, когда значения последовательности "x" назначаются одновременно. Если вы используете систему транзакций, в которой вы делаете одну вставку за раз - тогда кэширование бесполезно (или я должен сказать - я никогда не находил это полезным).

ПРИМЕЧАНИЕ. Это мое понимание опции кэширования последовательностей. Вы можете посмотреть документацию Oracle по командам CREATE SEQUENCE для получения дополнительной информации. Но ссылка выше должна дать разумный ответ на ваш вопрос.

Благодарю. Павел

Другое решение:

Используйте "GenerationType.AUTO" вместо "GenerationType.SEQUENCE" в качестве стратегии для @GeneratedValueкак показано ниже;

@Id
@SequenceGenerator(name = "studentId", sequenceName = "student_Id")
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId")  
private int studentId;

Одним из решений этой проблемы является настройка генератора последовательности с помощью allocSize:

@SequenceGenerator(name = "gen_name", sequenceName = "seq_name", allocationSize= 1)

Самый успешный ответ будет:

@Id
@SequenceGenerator (name = "id_sequence", sequenceName = "sq50")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_sequence")
public int getId() {
return id;
}

Как сказано здесь, попробуйте настроить ваш SequenceGenerator.allocationSize с вашей последовательностью базы данных INCREMENT BY число.

У меня были похожие проблемы. генератор последовательности и генератор последовательности очень похожи, но имеют различия. В hibernate 3 генератор hilo умножается на значение по умолчанию 50. Поэтому нет необходимости увеличивать последовательность DB. С другой стороны, в более поздних версиях hibernate по умолчанию используется генератор последовательностей. Поэтому приращение БД на 50 обязательно.

https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/Migration_Guide/Preserve_the_Existing_Behavior_of_the_Hibernate_Identity_Auto_Generated_Value1.html

У меня была эта проблема, которая имеет несколько спящих версий (3 и 5). Та же конфигурация работала нормально (увеличивается на 1 в БД). Но не удалось в hibernate 5. Поэтому я обновляю свой файл persistence.xml, как показано ниже. Это гарантирует поколение hilo

        <property name="hibernate.id.new_generator_mappings" value="false" />
Другие вопросы по тегам