Идентичные настройки базы данных Oracle: исключение только для одного из них - PullRequest
3 голосов
/ 16 мая 2011

edit: посмотрите в конце этого вопроса, что вызвало ошибку и как я узнал.

У меня очень странное исключение из Hibernate, когда я запускаю приложение, которое выполняет пакетную вставку данных в базу данных Oracle. Ошибка исходит из базы данных Oracle, ORA-00001 , которая

"означает, что была предпринята попытка вставить запись с дубликатом (уникальный) ключ. Эта ошибка также будет генерируется, если существующая запись обновлено для создания дубликата (уникальный) ключ. "

Ошибка странная, потому что я создал ту же таблицу (точно такое же определение) на другом компьютере, где я НЕ получаю ту же ошибку, если использую ее в своем приложении. И все данные вставляются в базу данных, так что на самом деле ничего не отклоняется.

Должно быть что-то разное между двумя настройками, но единственное, что я могу видеть, это различие - это вывод баннера, который я получаю при выдаче

select * from v$version where banner like 'Oracle%';

База данных, которая доставляет мне неприятности: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod
Тот, который работает: Oracle Database 10g Release 10.2.0.3.0 - 64bit Production

Определения таблиц, ввод и приложение, которое я написал, одинаковы для обоих. Используемая таблица представляет собой таблицу из четырех столбцов с составным идентификатором (serviceid, date, value1, value2) - ничего особенного.

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

Еще несколько выводов:

Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (STATISTICS.PRIMARY_KEY_CONSTRAINT) violated

    at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:367)
    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:8728)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)

Как я узнал, что вызвало проблему

Благодаря APC и ik_zelf мне удалось точно определить причину этой ошибки. Оказывается, планировщик Quartz был неправильно настроен для производственной базы данных (где обнаружена ошибка). Для работы, выполняемой на исправном сервере Oracle, у меня был <cronTriggerExpression>0/5 * * * * ?</cronTriggerExpression>, который запускал пакетное задание каждые пять секунд. Я подумал, что одной минуты достаточно для другого сервера Oracle и настроил кварцевый планировщик с помощью * * / 1 * * *?. Это оказывается неправильным, и вместо того, чтобы бегать каждую минуту, это бегало каждую секунду!

Каждое задание занимало приблизительно 1,5-2 секунды, и, следовательно, два или более заданий выполнялись одновременно, вызывая одновременные вставки на сервер. Поэтому вместо вставки 529 элементов я получал от 1000 до 2000 вставок. Изменение выражения crontrigger на то же, что и другое, выполняемое каждые пять секунд, устранило проблему.

Чтобы выяснить, в чем дело, мне пришлось установить значение true в hibernate.cfg.xml и отключить ограничение первичного ключа для таблицы.

-- To catch exceptions
-- to find the offending rows run the following query
-- SELECT * FROM uptime_statistics, EXCEPTIONS WHERE MY_TABLE.rowid = EXCEPTIONS.row_id;
create table exceptions(row_id rowid,
                        owner varchar2(30),
                        table_name varchar2(30),
                        constraint varchar2(30));

-- This table was set up
CREATE TABLE MY_TABLE
  (
    LOGDATE DATE NOT NULL,
    SERVICEID           VARCHAR2(255 CHAR) NOT NULL,
    PROP_A   NUMBER(10,0),
    PROP_B NUMBER(10,0),
    CONSTRAINT PK_CONSTRAINT PRIMARY KEY (LOGDATE, SERVICEID)
  );

-- Removed the constraint to see what was inserted twice or more
alter table my_table
  disable constraint PK_CONSTRAINT;

-- Enable this later on to find rows that offend the constraints
alter table my_table
  enable constraint PK_CONSTRAINT
    exceptions into exceptions;

Ответы [ 3 ]

4 голосов
/ 17 мая 2011

У вас есть уникальное составное ограничение.ORA-00001 означает, что у вас есть две или более строки с одинаковыми значениями в ServiceID, Date, Value1 и / или Value2.Вы говорите, что ввод одинаков для обеих баз данных.Так что либо:

  • вы представляете, что ваша программа швыряет ORA-00001
  • , вы ошибаетесь, что ввод одинаков в обоих прогонах.

Более вероятное объяснение - второе: один или несколько ваших ключевых столбцов заполнены внешним источником или значением по умолчанию (например, таблица кодов для ServiceId или SYSDATE для столбца даты).В вашей базе данных с ошибками это автоматическое заполнение не может предоставить уникальное значение.Причин может быть несколько, в зависимости от того, какой механизм (ы) вы используете.Помните, что в уникальном составном ключе учитывается NULL записей.То есть вы можете иметь любое количество записей (NULL, NULL.NULL, NULL), но только одну для (42, NULL, NULL, NULL).

Нам трудно угадать, в чем проблема на самом делеможет быть, и почти так же сложно для вас (хотя у вас есть преимущество в том, чтобы быть автором кода, что должно дать вам некоторое понимание).То, что вам нужно, это некоторые следовые заявления.Моим предпочтительным решением было бы использовать Bulk DML Exception Handling , но тогда я фанат PL / SQL.Hibernate позволяет подключить некоторые программы к вашим программам: я предлагаю вам включить их.Код намного проще для отладки, когда он имеет приличную аппаратуру.

В качестве крайней меры отключите ограничение перед запуском пакетной вставки.Затем снова включите его следующим образом:

alter table t42
    enable constraint t42_uk
        exceptions into my_exceptions
/

Это не удастся, если у вас есть повторяющиеся строки, но, что важно, в таблице MY_EXCEPTIONS будут перечислены все строки, которые конфликтуют.По крайней мере, это даст вам некоторое представление об источнике дублирования.Если у вас еще нет таблицы исключений, вам придется запустить скрипт: $ORACLE_HOME/rdbms/admin/utlexcptn.sql (вам может потребоваться администратор базы данных для получения доступа к этому каталогу).


tl; dr

Для понимания требуется информация: введите ваш код.

1 голос
/ 17 мая 2011

Я думаю, это будет идентификатор сервиса. Какой бы сервисный идентификатор hibernate не использовал для «свежей» вставки, уже был использован.

Возможно, таблица пуста в одной базе данных, но заполнена в другой

Могу поспорить, что service_id генерируется последовательность, а порядковый номер не синхронизирован с содержанием данных. Таким образом, у вас есть те же 1000 строк в таблице, но вы делаете

SELECT service_id_seq.nextval FROM DUAL

в одной базе данных дает меньшее число, чем в другой. Я часто вижу это, когда последовательность была создана (например, из-под контроля исходного кода) и данные были импортированы в таблицу из другой базы данных.

1 голос
/ 16 мая 2011

У одного, у которого есть проблемы, есть EE, а у другого - база данных SE.Я ожидаю, что первый на более быстром оборудовании.Если это так, и ваш столбец даты заполнен с использованием SYSDATE, вполне возможно, что временного разрешения недостаточно;что вы получаете повторяющиеся значения даты.Если другие столбцы ваших данных также не являются уникальными, вы получаете ORA-00001.

Это длинный выстрел, но на первый взгляд я бы посмотрел в этом направлении.

Можете ли вы использовать исключениетаблица для идентификации данных?См. Отчет об исключениях для ограничений

...