Нарушение уникального ограничения на вставку после перезапуска сервера

Я использую сервер JBoss EAP 7 с базой данных Oracle 11g и Hibernate для JPA. Я заметил что-то странное. Когда я впервые создаю базу данных и запускаю сервер, все работает нормально. Я отправляю запросы от клиента и сервер сохраняет данные в БД.

Если я перезагружаю сервер и пытаюсь сделать то же самое, я получаю уникальное исключение нарушения ограничения для каждого запроса:

java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (SCHEMA.SYS_C0010299) violated

at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:447)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:951)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:513)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:208)
at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1046)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1336)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3613)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3694)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1354)
at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:537)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)

Я проверил ограничение в sqlplus с помощью запроса ниже. (Я выполнил запрос как системный пользователь, а не как пользователь сервера, если это имеет значение).

SELECT A.TABLE_NAME,C.TABLE_NAME,COLUMN_NAME FROM ALL_CONS_COLUMNS A
JOIN ALL_CONSTRAINTS C ON A.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE C.CONSTRAINT_NAME = 'SYS_C0010299';

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

@Id
@Column(name="ID_COL")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "SEQ_NAME_GEN")
@SequenceGenerator(name = "SEQ_NAME_GEN", sequenceName = "SEQ_NAME")
private Long id;

Если я создаю новую новую БД, сначала приложение снова работает нормально, пока я не перезагружу сервер. Почему это происходит?

Это отношение класса сущности к другому классу сущности:

// other class
@OneToMany(cascade=CascadeType.ALL, mappedBy="otherClass")
@MapKey(name = "mapKey")
private Map<MapKey, ConstraintViolationEntityClass>
    map;

// problematic class (ConstraintViolationEntityClass)
@Column(name = "MAP_KEY")
@Enumerated(EnumType.ORDINAL)
private EnumType enumType;
@ManyToOne
@JoinColumn(name = "OTHER_CLASS_ID", nullable = false)
private OtherClass otherClass;

И это код SQL, который я использовал для создания таблицы для ConstraintViolationEntityClass:

create table schema.ConstraintViolationEntityTable (
  id_col number(10) not null primary key,
  map_key number(2) not null,
  other_class_id number(10) not null,
  constraint other_class_fk foreign key (other_class_id) references schema.other_class(id)
);

Это мой файл persistence.xml:

<persistence-unit name="unit1" transaction-type="JTA">
  <jta-data-source>java:jboss/OracleDS</jta-data-source>
  <exclude-unlisted-classes>false</exclude-unlisted-classes>
  <properties>
    <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
    <property name="hibernate.show_sql" value="true" />
    <property name="hibernate.format_sql" value="true" />
    <property name="hibernate.hbm2ddl.auto" value="validate" />
  </properties>
</persistence-unit>

По некоторым причинам некоторые из первичных ключей строк, вставленных успешными запросами, являются отрицательными. И проверка dba_sequences, last_number последовательности составляет 43, даже если в таблице всего 24 строки (12 запросов добавляются на запрос клиента)

1 ответ

Решение

Как указано в ответе, с которым связывается PeterM, размер выделения по умолчанию для генераторов последовательностей равен 50, что является основной причиной проблемы, поскольку вы определили последовательность с шагом 1. Я просто прокомментирую проблему отрицательных значений.,

Размер выделения 50 (установлен в SequenceGenerator.allocationSize) означает, что Hibernate будет:

  • создать последовательность с INCREMENT BY 50 (если позволите)
  • захватить следующее значение n из последовательности
  • начать выделять идентификаторы из n-50 до n
  • Повторите два шага выше, как только он заканчивается чисел

Поскольку вы увеличили последовательность на 1, легко увидеть, откуда приходят отрицательные значения (и почему последуют нарушения ограничений). Если вы попытаетесь вставить более 50 строк, вы столкнетесь с нарушениями ограничений без перезагрузки сервера.

Другие вопросы по тегам