Hibernate - пакетное обновление возвращало неожиданный счетчик строк из обновления: 0 фактическое количество строк: 0 ожидаемых: 1

Я получаю следующую спящую ошибку. Я могу определить функцию, которая вызывает проблему. К сожалению, в функции есть несколько вызовов БД. Я не могу найти строку, которая вызывает проблему, поскольку hibernate завершает сеанс в конце транзакции. Ниже приведенная ошибка спящего режима выглядит как общая ошибка. В нем даже не упоминается, какой из Bean вызывает проблему. Любой, кто знаком с этой ошибкой спящего режима?

org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
        at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.java:93)
        at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:79)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransacti
onManager.java:500)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManag
er.java:473)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.doCommitTransactionAfterReturning(Transaction
AspectSupport.java:267)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)

Ответ 1

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

Однако, чтобы лучше понять причину проблемы, попробуйте следующее:

  • В вашей конфигурации спящего режима установите для hibernate.show_sql значение true. Это должно показать вам SQL, который выполняется и вызывает проблему.
  • Задайте уровни журналов для Spring и Hibernate для DEBUG, это даст вам более полное представление о том, какая строка вызывает проблему.
  • Создайте unit test, который реплицирует проблему без настройки диспетчера транзакций в Spring. Это должно дать вам лучшее представление о нарушении кода.

Надеюсь, что это поможет.

Ответ 2

Я получил то же исключение, удалив запись с помощью идентификатора, который вообще не существует. Поэтому проверьте, что запись, которую вы обновляете /Deleting, фактически существует в DB

Ответ 3

Решение: В файле сопоставления Hibernate для свойства id, если вы используете какой-либо класс генератора, для этого свойства вы не должны явно устанавливать значение с помощью метода setter.

Если вы зададите значение свойства Id явно, это приведет к ошибке выше. Проверьте это, чтобы избежать этой ошибки. или Это ошибка показывает, когда вы указываете в файле сопоставления генератор полей = "native" или "incremental", а в вашей базе данных таблица, отображаемая не является auto_incremented Решение. Перейдите на свою базу данных и обновите таблицу, чтобы установить auto_increment

Ответ 4

Это случилось со мной однажды, когда я назначал определенные идентификаторы некоторым объектам (тестирование), а затем я пытался их сохранить в базе данных. Проблема заключалась в том, что в базе данных была определенная политика для создания идентификаторов объектов. Просто не присваивать идентификатор, если у вас есть политика на уровне Hibernate.

Ответ 5

В моем случае я пришел к этому исключению в двух похожих случаях:

  • В методе, аннотированном с помощью @Transactional, у меня был вызов в другую службу (с большим временем ответа). Метод обновляет некоторые свойства объекта (после метода объект все еще существует в базе данных). Если пользователь дважды запрашивает метод (поскольку он считает, что он не работает в первый раз) при выходе из транзакционного метода во второй раз, Hibernate пытается обновить сущность, которая уже изменила свое состояние с начала транзакции. Когда Hibernate ищет сущность в состоянии и обнаруживает ту же сущность, но уже измененную первым запросом, он выдает исключение, поскольку не может обновить сущность. Это как конфликт в ЖКТ.
  • У меня были автоматические запросы (для мониторинга платформы), которые обновляют сущность (и откат вручную через несколько секунд). Но эта платформа уже используется командой тестирования. Когда тестер выполняет тест в том же объекте, что и автоматические запросы (в пределах одной сотой миллисекунды), я получаю исключение. Как и в предыдущем случае, при выходе из второй транзакции ранее извлеченный объект уже изменился.

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

Решение: чтобы решить эту проблему, вам придется поработать с LockMode Hibernate, чтобы найти тот, который наилучшим образом соответствует вашим требованиям.

Ответ 6

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

SET NOCOUNT ON;

Ответ 7

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

Ответ 8

Я столкнулся с такой же проблемой. Код работал в тестовой среде. Но он не работал в промежуточной среде.

org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1

Проблема заключалась в том, что в таблице была одна запись для каждого первичного ключа при тестировании таблицы БД. Но в промежуточной БД было несколько записей для того же первичного ключа. (Проблема заключается в промежуточном БД, в таблице не было ограничений первичного ключа, также было несколько записей.)

Поэтому каждый раз при обновлении он получает сбой. Он пытается обновить одну запись и ожидать, что количество обновлений будет равным 1. Но поскольку в таблице для одного и того же первичного ключа было 3 записи, число результатов обновления результата 3. Поскольку ожидаемое количество обновлений и фактический результат обновления не совпадают, Он выдает исключение и откатывается.

После того, как я удалил все записи, которые имеют дублирующий первичный ключ и добавили ограничения первичного ключа. Он работает нормально.

Hibernate - Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1

фактическое количество строк: 0//означает, что не найдена запись для обновления
update: 0//означает, что запись не найдена, поэтому ничего не обновляется
Ожидаемый: 1//означает, что ожидается как минимум 1 запись с ключом в таблице db.

Здесь проблема в том, что запрос пытается обновить запись для некоторого ключа, но hibernate не нашел записи с ключом.

Ответ 9

Я столкнулся с этой проблемой, когда у нас было отношение "один-много".

В файле сопоставления hibm hibm для master для объекта с настройкой типа набора добавлен cascade="save-update", и он работал нормально.

Без этого по умолчанию hibernate пытается обновить несуществующую запись и тем самым вставляет вместо нее.

Ответ 10

Как Julius говорится, что это происходит, когда обновление возникает у объекта, у которого его дети удаляются. (Возможно, потому что возникла необходимость в обновлении для всего объекта Отца, и иногда мы предпочитаем удалять детей и повторно вставлять их в Отца (новый, старый не имеет значения) вместе с любыми другими обновлениями, которые отец мог иметь на любом из его другие равнинные поля) Итак... чтобы это могло работать, удалите дочерние элементы (внутри транзакции), вызвав childrenList.clear() (Dont прокручивает дочерние элементы и удаляет каждый из них с помощью childDAO.delete(childrenList.get(i).delete())) и настройки @OneToMany(cascade = CascadeType.XXX ,orphanRemoval=true) на стороне объекта Отца. Затем обновите отца (fatherDAO.update(отец)). (Повторите для каждого объекта-отца). В результате дети привязаны к отцу, а затем их удаляют как сироты с помощью рамки.

Ответ 11

Это также может произойти, когда вы пытаетесь обновить UPDATE ключ.

Ответ 12

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

Ответ 13

Другой способ получить эту ошибку, если у вас есть нулевой элемент в коллекции.

Ответ 14

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

session.clear();

Ответ 15

Это случилось со мной, потому что у меня был мой идентификатор Long, и я получал от представления значение 0, и когда я попытался сохранить в базе данных, я получил эту ошибку, затем исправил ее, установив id to null.

Ответ 16

Я столкнулся с этой проблемой, когда я начинал вручную и совершал транзакции внутри метода, аннотированного как @Transactional. Я исправил проблему, обнаружив, что активная транзакция уже существует.

//Detect underlying transaction
if (session.getTransaction() != null && session.getTransaction().isActive()) {
    myTransaction = session.getTransaction();
    preExistingTransaction = true;
} else {
    myTransaction = session.beginTransaction();
}

Затем я разрешил Spring обрабатывать транзакцию.

private void finishTransaction() {
    if (!preExistingTransaction) {
        try {
            tx.commit();
        } catch (HibernateException he) {
            if (tx != null) {
                tx.rollback();
            }
            log.error(he);
        } finally {
            if (newSessionOpened) {
                SessionFactoryUtils.closeSession(session);
                newSessionOpened = false;
                maxResults = 0;
            }
        }
    }
}

Ответ 17

Это происходит, когда вы объявили JSF Managed Bean как

@RequestScoped;

когда вы должны объявить как

@SessionScoped;

Привет;

Ответ 18

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

Ответ 19

Я также столкнулся с тем же вызовом. В моем случае я обновлял объект, который даже не существовал, используя hibernateTemplate.

Фактически в моем приложении я получал объект базы данных для обновления. И, обновляя его значения, я также по ошибке обновил его идентификатор и пошел дальше, чтобы обновить его и наткнулся на указанную ошибку.

Я использую hibernateTemplate для операций CRUD.

Ответ 20

После прочтения всех ответов не было никого, кто мог бы говорить об обратном атрибуте спящего режима.

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

Предположим, что у нас есть две таблицы:

main_table, middle_table

с отношением от одного до многих. Классы отображения hiberntate Основные и Средние соответственно.

Итак, класс Principal имеет SET из Средних объектов. Файл сопоставления xml должен выглядеть следующим образом:

<hibernate-mapping>
    <class name="path.to.class.Principal" table="principal_table" ...>
    ...
    <set name="middleObjects" table="middle_table" inverse="true" fetch="select">
        <key>
            <column name="PRINCIPAL_ID" not-null="true" />
        </key>
        <one-to-many class="path.to.class.Middel" />
    </set>
    ...

В качестве инверсного значения установлено значение "истина", это означает, что "средний" класс является владельцем отношений, поэтому класс Principal будет NOT UPDATE.

Итак, процедура обновления может быть реализована следующим образом:

session.beginTransaction();

Principal principal = new Principal();
principal.setSomething("1");
principal.setSomethingElse("2");


Middle middleObject = new Middle();
middleObject.setSomething("1");

middleObject.setPrincipal(principal);
principal.getMiddleObjects().add(middleObject);

session.saveOrUpdate(principal);
session.saveOrUpdate(middleObject); // NOTICE: you will need to save it manually

session.getTransaction().commit();

Это сработало для меня, вы можете предложить некоторые издания, чтобы улучшить решение. Таким образом, мы все будем учиться.

Ответ 21

Это произошло, если вы изменили что-то в наборе данных, используя собственный SQL-запрос, но сохраняемый объект для того же набора данных присутствует в кеше сеанса. Используйте session.evict(yourObject);

Ответ 22

Спящий режим кэширует объекты из сеанса. Если объект доступен и изменен более чем одним пользователем, тогда может быть выбрано org.hibernate.StaleStateException. Он может быть решен с помощью метода объединить/обновить объект перед сохранением или использованием блокировки. Дополнительная информация: http://java-fp.blogspot.lt/2011/09/orghibernatestalestateexception-batch.html

Ответ 23

Один из случаев

SessionFactory sf=new Configuration().configure().buildSessionFactory();
Session session=sf.openSession();

UserDetails user=new UserDetails();

session.beginTransaction();
user.setUserName("update user agian");
user.setUserId(12);
session.saveOrUpdate(user);
session.getTransaction().commit();
System.out.println("user::"+user.getUserName());

sf.close();

Ответ 24

Я получил эту ошибку, потому что ошибочно сопоставил столбец ID, используя Id(x => x.Id, "id").GeneratedBy.**Assigned**();

Проблема разрешена с помощью Id(x => x.Id, "id").GeneratedBy.**Identity**();

Ответ 25

Я столкнулся с этим исключением, и спящий режим работал хорошо. Я попытался вставить вручную одну запись с помощью pgAdmin, здесь проблема стала очевидной. SQL insert query возвращает 0 insert. и есть триггерная функция, вызывающая эту проблему, поскольку она возвращает значение null. поэтому я должен только установить его для возврата нового. и, наконец, я решил проблему.

Надеюсь, что это поможет любому телу.

Ответ 26

Это происходит со мной, потому что мне не хватает объявления идентификатора в классе бина.

Ответ 27

В моем случае была проблема с базой данных, так как один из хранимых процессоров потреблял весь процессор, вызывая большое время отклика БД. Как только это было убито, проблема была решена.

Ответ 28

На самом деле, это случилось со мной, когда я не сохранил объект в качестве ссылочной переменной. в классе сущности. Понравился этот код: ses.get(InsurancePolicy.class, 101); После этого я сохранил объект в ссылочной переменной сущности, так что проблема для меня решена. policy=(InsurancePolicy)ses.get(InsurancePolicy.class, 101); После этого я обновил объект, и он работал нормально.

Ответ 29

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

Ответ 30

Несколько способов отладки этой ошибки:

  1. Как предложено в принятом answer- включите шоу sql.
  2. Я обнаружил, что есть некоторые проблемы с настройкой идентификатора в Hibernate SQL.
  3. Обнаружил, что мне не хватает @GeneratedValue (стратегии = GenerationType.IDENTITY)