Вопрос

есть ли решение для пакетной вставки через hibernate в секционированную таблицу postgresql?в настоящее время я получаю сообщение об ошибке, подобное этому...

ERROR org.hibernate.jdbc.AbstractBatcher - Exception executing batch:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
   at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
   at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
   at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:68)....

я нашел эту ссылку http://lists.jboss.org/pipermail/hibernate-dev/2007-October/002771.html но я нигде не могу найти в Интернете, решена ли эта проблема или как ее можно обойти

Это было полезно?

Решение

Возможно, вы захотите попробовать использовать пользовательский пакет, установив свойство hibernate.jdbc.factory_class.Убедившись, что hibernate не будет проверять количество обновлений пакетных операций, вы можете решить вашу проблему, вы можете добиться этого, заставив свой пользовательский пакетчик расширить класс BatchingBatcher, а затем переопределив метод doExecuteBatch (...), чтобы он выглядел как:

    @Override
    protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException {
        if ( batchSize == 0 ) {
            log.debug( "no batched statements to execute" );
        }
        else {
            if ( log.isDebugEnabled() ) {
                log.debug( "Executing batch size: " + batchSize );
            }

            try {
//              checkRowCounts( ps.executeBatch(), ps );
                ps.executeBatch();
            }
            catch (RuntimeException re) {
                log.error( "Exception executing batch: ", re );
                throw re;
            }
            finally {
                batchSize = 0;
            }

        }

    }

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

Другие советы

Они говорят использовать два триггера в секционированной таблице или аннотацию @SQLInsert здесь: http://www.redhat.com/f/pdf/jbw/jmlodgenski_940_scaling_hibernate.pdf страницы 21-26 (там также упоминается @SQLInsert, указывающий строковый метод).

Вот пример с триггером after для удаления дополнительной строки в главном файле: https://gist.github.com/copiousfreetime/59067

Появляется, если вы можете использовать ПРАВИЛА вместо триггеров для вставки, тогда это может вернуть правильное число, но только с одним ПРАВИЛОМ без оператора WHERE.

ссылка 1

ссылка 2

ссылка 3

другим вариантом может быть создание представления, которое "оборачивает" секционированную таблицу, затем вы возвращаете НОВУЮ строку, чтобы указать на успешное обновление строки, без случайного добавления дополнительной нежелательной строки в основную таблицу.

create view tablename_view as select * from tablename; -- create trivial wrapping view

CREATE OR REPLACE FUNCTION partitioned_insert_trigger() -- partitioned insert trigger
RETURNS TRIGGER AS $$
BEGIN
   IF (NEW.partition_key>= 5500000000 AND
       NEW.partition_key <  6000000000) THEN
      INSERT INTO tablename_55_59 VALUES (NEW.*);
   ELSIF (NEW.partition_key >= 5000000000 AND
          NEW.partition_key <  5500000000) THEN
      INSERT INTO tablename_50_54 VALUES (NEW.*);
   ELSIF (NEW.partition_key >= 500000000 AND
          NEW.partition_key  <  1000000000) THEN
      INSERT INTO tablename_5_9 VALUES (NEW.*);
   ELSIF (NEW.partition_key >= 0 AND
          NEW.partition_key <  500000000) THEN
      INSERT INTO tablename_0_4 VALUES (NEW.*);
   ELSE
      RAISE EXCEPTION 'partition key is out of range.  Fix the trigger function';
   END IF;
   RETURN NEW; -- RETURN NEW in this case, typically you'd return NULL from this trigger, but for views we return NEW
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER insert_view_trigger
   INSTEAD OF INSERT ON tablename_view
   FOR EACH ROW EXECUTE PROCEDURE partitioned_insert_trigger(); -- create "INSTEAD OF" trigger

ссылка: http://www.postgresql.org/docs/9.2/static/trigger-definition.html

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

Другой вариант, который использует представление, - создать правило вставки, чтобы все вставки в основной таблице переходили в представление [которое использует свой триггер], например (при условии, что у вас уже есть partitioned_insert_trigger и tablename_view и insert_view_trigger созданы, как указано выше)

create RULE use_right_inserter_tablename AS
      ON INSERT TO tablename
      DO INSTEAD insert into tablename_view VALUES (NEW.*);

Затем он будет использовать вашу новую вставку-оболочку рабочего вида.

спасибо!это сделало свое дело, пока никаких проблем не возникло :) .... одно но...я должен был реализовать BatcherFactory класс и поместите его в persistence.xml файл, вот такой:

property name="hibernate.jdbc.factory_class" value="path.to.my.batcher.factory.implementation"

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

ps ядро гибернации 3.2.6 GA

еще раз спасибо

Я столкнулся с той же проблемой при вставке документов через hibernate после долгих поисков обнаружил, что ожидается, что обновленные строки должны быть возвращены, поэтому вместо null измените его на new в процедуре запуска, которая решит проблему, как показано ниже

ВЕРНУТЬ НОВЫЙ

Я нашел другое решение той же проблемы на этой веб-странице:

Это предполагает то же самое решение, о котором сказал @rogerdpack, изменив Возвращает значение Null Для Вернуть НОВЫЙ, и добавление нового триггера , который удаляет дублированный кортеж в главном файле вместе с запросом:

DELETE FROM ONLY master_table;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top