mariadb Hibernate批次更新问题

jhiyze9q  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(181)

对于正确Map为Hibernate实体类的MariaDB表的简单批处理更新,通过Hibernate进行简单更新会产生以下错误

org.hibernate.StaleStateException: Batch update returned unexpected row count from update

每个表记录都由Entity类建模,这是一个简单的POJO,需要更新(如果它已经存在)或作为新对象插入(如果它在表中不存在),它有一个主id字段(不是自动递增的)和一些其他值,都是标量。

public static void update(Set<Long> ids) {
  Session session = createSession();
  Transaction t = session.beginTransaction();
  try {
    for (Long id : ids) {
      Entity entity = session.get(Entity.class, id);
      if (entity == null) {
        entity = new Entity();
      }
      entity.setId(id);
      // Other entity value settings
      session.saveOrUpdate(entity);
    }
    transaction.commit();
  } catch (Exception e) {
    transaction.rollback();
  } finally {
    session.close();
  }
}

在Hibernate中实现上述操作的正确方法是什么?

6ojccjat

6ojccjat1#

您以这种方式使用saveOrUpdate(),Hibernate通过自己的逻辑决定什么是新的( transient )对象,什么是旧的(持久化)对象,并根据这一点相应地执行save()update()方法。

在下列情况下,Hibernate会假设执行严修是未储存的暂时执行严修:

  • 标识符属性为null
  • 版本或时间戳属性(如果存在)为null
  • 由Hibernate在内部创建的同一持久性类的新示例与给定示例具有相同的数据库标识符值。
  • 您在类的Map文档中提供了一个unsaved-value,标识符属性的值匹配。unsaved-value属性也可用于版本和时间戳Map元素。
  • 具有相同标识符值的实体数据不在二级缓存中。
  • 您可以提供实作或org.hibernate.Interceptor,并在程式码中检查执行严修之后,从Interceptor.isUnsaved()传回Boolean.TRUE
    **否则:**实体将被确定为已保存的持久实体

在您的示例中,Hibernate没有确定新的( transient )对象,因此,对它执行update()方法。它生成UPDATE而不是INSERT语句。UPDATE语句对不存在的记录返回零个更新的记录,因此这就是您的异常的原因。

**解决方案:**为新实体显式使用save()方法:

public void update(Set<Long> ids) {
        Session session = getSessionFactory().openSession();
        Transaction transaction = session.beginTransaction();
        try {
            for (Long id : ids) {
                HibernateEntity entity = session.get(HibernateEntity.class, id);
                if (entity == null) {
                    entity = new HibernateEntity();
                }
                // Other entity value settings
                entity.setValue(entity.getValue() + "modification");

                if (entity.getId() == null) {
                    entity.setId(id);
                    session.save(entity);
                }
            }
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        } finally {
            session.close();
        }
    }

update()方法不需要显式调用。事务持久性示例(即由会话加载、保存、创建或查询的对象)可以由应用程序操作,并且当会话为flushed时,对持久性状态的任何更改都将被持久化。根据文档。

相关问题