Я использую сервер 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 строк добавляются на каждый запрос клиента)
SequenceGenerator
по умолчанию - 50. Каков размер приращения вашей последовательности? - person Rohit   schedule 09.04.2018persistence.xml
используетhibernate.hbm2ddl.auto=validate
, как вы генерируете базу данных? Возможно ли, что последовательность будет создана иначе, чем если бы использовалсяhibernate.hbm2ddl.auto=create-drop
? - person crizzis   schedule 09.04.2018create sequence SEQ_NAME start with 1;
. Как я могу проверить, отличается ли это от того, что требуется для гибернации? - person devil0150   schedule 10.04.2018all_sequences
. вы также можете попробовать использовать инструмент создания схемы, как описано здесь: access.redhat.com/documentation/en-us/ - person crizzis   schedule 10.04.2018create-drop
и увидел операторы sql, которые спящий режим использует для создания последовательностей. Единственная разница былаincrement by 50
. Я модифицировал свой собственный сценарий, чтобы использовать его, и теперь он работает. Можете ли вы или PeterM написать это в качестве ответа? Если у вас есть объяснение, почему это может привести к нарушению ограничений и отрицательным идентификаторам, включите его. - person devil0150   schedule 10.04.2018@SequenceGenerator
: docs.oracle.com/javaee/7/api/javax/persistence/. - person crizzis   schedule 11.04.2018