当前位置: 首页 > 知识库问答 >
问题:

间歇性错误org.hibernate.持久性对象异常:传递给持久性的分离实体

秦光启
2023-03-14

我得到了异常org.hibernate.持久性对象异常:分离实体传递到持久性。从这个论坛和其他地方的许多帖子中,我知道这种情况发生在两种情况下(不考虑一对一注释等),

  1. 交易超出范围存在问题
  2. 在自动生成id的位置设置id

我在代码中没有看到这两种情况。我无法重现错误,因为我没有最初触发它的数据。在其他数据上,它运行得非常好。我提供了下面的SCCE:

public class MyProcessor {
    private MyImportEJB myEJB = MyImportEJB.getInstance();
    private List<MyClass> saveQueue = new ArrayList<MyClass>();
    public void process() {
        List<X> rawData = getListOfX();
        for(X x:rawData) {
             processX();
         }
         saveFoos(saveQueue);   
     }

     public void saveOrUpdateFoos(List<Foo> foos) {

        for(MyClass foo:foos) {
              MyClass existingFoo = myEJB.getFoosForWidAndDates(foo.getWid(), foo.getEffBeginDt(),foo.getEffEndDt());
              if(existingFoo == null) saveQueue.add(foo);
              else {
                   existingFoo.updateIfDifferent(foo);
                   saveQueue.add(existingFoo);
              }
         }

         if(saveQueue.size() > 5000) {
             myEJB.saveObjects(saveQueue);
             saveQueue.clear();
         }
     }

     public void processX() {
          ArrayList<MyClass> foos = new ArrayList<MyClass>();

          if(x.reportPeriod != null && x.gravity != null){
              MyClass foo = new MyClass();
              foo.setId(null);
              foo.setWId(x.getWid());
              foo.setEffBeginDt(x.reportPeriod);
              foo.setEffEndDt(addOneMonth(x.reportPeriod));
              foo.setGravity(x.gravity);

              foos.add(foo);
          }
          saveOrUpdateFoos(foos);

     }
 }

MyImportEJB。爪哇:

@Stateless
@EJB(name = "MyImportEJB", beanInterface = MyImportEJB.class)
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@PermitAll
public class MyImportEJB{
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void saveObjects(List<? extends P> mappedObjects) 
    {
        for (P mappedObject : mappedObjects)
        {
            this.saveObject(mappedObject);
        }
    }


    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void saveObject(P mappedObject) 
    {
        EntityManager entityManager = this.getEntityManager();

        Object identifier = this.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(mappedObject);
        if (identifier != null) {
            Object existingObject = entityManager.find(mappedObject.getClass(), identifier);

            if (existingObject != null) {
                entityManager.merge(mappedObject);
                return;
            }
         }

         entityManager.persist(mappedObject);
    }

    public MyClass getFoosForWidAndDates(Integer wid, Calendar effBeginDt, Calendar effEndDt) {
         try {
            return (MyClass)((this.entityManager
        .createQuery("select M from MyClass M where wid = :wid and effBeginDt = :effBeginDt and effEndDt = :effEndDt ", MyClass.class)
        .setParameter("wid",wid)
        .setParameter("effBeginDt", effBeginDt)
        .setParameter("effEndDt", effEndDt)).getSingleResult());
         } catch(NoResultException | NonUniqueResultException e) {
            return null;
        }
    }
 }

我的班级。JAVA

public MyClass{

      @Id
      @GeneratedValue(strategy=GenerationType.IDENTITY)
      @Column(name = "Id")
      private Integer id;

      @Column(name = "wid")
      private Integer wId;

      @Column(name = "eff_begin_dt")
      private Calendar effBeginDt;

      @Column(name = "eff_end_dt")
      private Calendar effEndDt;

      @Column(name = "gravity")
      private Double gravity;

      private Integer dataDownloadId;

      public void updateIfDifferent(MyClass other) {
          if(other.gravity != null && other.gravity != this.gravity) this.gravity = other.gravity;
          //same for effBeginDt andeffEndDt

      }

 }

坚持不懈xml

  <?xml version="1.0" encoding="UTF-8" ?>

 <persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
    <persistence-unit name="ProdData">
        <description>ProdData Database Persistence Unit</description>
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:jboss/ProdDataJNDI</jta-data-source>
        <class>path.to.MyClass</class>
        <class>path.to.X</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.show_sql" value="false" />
         </properties>
    </persistence-unit>
 </persistence>

调用entityManager.persist时引发异常

我试着编写一个示例程序,从数据库中获取一个现有的foo对象,更新并保存它,因为这是最可能的错误源。但我无法重现这个错误。请帮忙。

编辑:以下是getListofX()的详细信息

来自MyProcessor.java:

public List<X> getListOfX() {
    return myImportEJB.getUnprocessedIds(X.class, 30495);
}

从文件MyImportEJB。爪哇:

@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<Integer> getUnprocessedIds(Class<? extends ProductionRawData> clazz, Integer dataDownloadId) {
    String canonicalName = clazz.getCanonicalName();

    String queryStr = "select id from " + canonicalName + " where datadownloadId = :dataDownloadId and isProcessed != 1";

    TypedQuery<Integer> query = this.entityManager.createQuery(queryStr, Integer.class)
        .setParameter("dataDownloadId", dataDownloadId);
    try {
        return query.getResultList();
    } catch(NoResultException nre) {
         return new ArrayList<T>();
    }
}

编辑:还添加了getFoosForWidAndDates()的详细信息。有人建议我在将新Foo添加到保存队列之前将其id设置为空。我想知道是否有可能Hibernate将id设置为“引擎盖下”的不可接受值

共有3个答案

邹博明
2023-03-14

我再次在生产服务器上运行了代码,在分离的实体异常之前,我得到了TransactionRollbackException。我认为这可能是我观察到的异常的实际原因。

由于我试图保存的对象数量巨大,事务超时并被回滚,这导致Foo对象变得分离。不知何故,TransactionRollback异常第一次没有出现在日志中,可能是因为它恰好发生在犹他州上午12点。为了支持这一理论,在我将批量大小降低到~1000之后,程序还没有崩溃

对于那些感兴趣的人来说,TransactionRollbackException确实会导致实体分离:entityManager。getTransaction()。rollback()分离实体?

出现这种情况时,有很多方法可以处理,但为了简单起见,我选择不实现它们

尹弘壮
2023-03-14

我希望您使用的是最新的Hibernate。我认为这是一个打字错误:

if(existingFoo == null) saveQueue.add(existingFoo); // if it is a null, you add it?

否则它看起来很有趣,你可以尝试做以下事情:

>

  • 在每个(10,1000)持久化对象之后刷新会话,如下所示:

    public void saveObjects(List<? extends P> mappedObjects) 
    {
        for (P mappedObject : mappedObjects)
        {
            this.saveObject(mappedObject);
            // some condition if you have a lot of objects
            this.entityManager.flush();
        }
    }
    

    使用不那么奇怪的方法检查实体是否已被持久化:

    public void saveObject(P mappedObject) {
        EntityManager entityManager = this.getEntityManager();
    
        if (mappedObject.getId() != null) {
            entityManager.merge(mappedObject);
            return;
         }
    
         entityManager.persist(mappedObject);
    }
    

    或者最好完全避免合并,只处理托管对象,这将需要对所有操作进行单个事务处理,因此需要重新设计这些东西。

  • 咸昀
    2023-03-14

    我想这可能是你的问题

     if(saveQueue.size() > 5000) {
         myEJB.saveObjects(saveQueue);
         saveQueue.clear();
     }
    

    您要将保存队列填充到5000个,然后尝试将它们持久化/合并。我不确定Hibernate,但EclipseLink的默认共享缓存大小是1000。这意味着,您可以使用现有的2000个Foos来填充saveQueue,当您对它们调用persist()时,它们不再位于实体管理器的缓存中。这将导致对已设置了id的分离实例调用persist()

    在你的例子中,我认为在所有对象上调用entityManager.merge(mapepdObject)是完全可以的,不管它是否是一个现有的对象,因为它将更新现有的对象,并保留新的对象。

     类似资料:
    • 问题内容: 我正在创建一个简单的应用程序,只需使用将一行插入到表中(如果表不存在,则创建它)。 我为它的一个可运行示例附加了一些代码。 这是我得到的异常和stacktrace: 这是我的代码: 主班: 和Person类: 这是我的persistence.xml文件 -----------------------编辑-------------------------- – 我只是将提供程序更改为Ec

    • 调用init方法失败;嵌套的异常是javax。坚持不懈PersistenceException:[PersistenceUnit:默认值]无法生成Hibernate SessionFactory 在更换系统中的操作系统后,我遇到了这个异常。在我的应用程序运行MySQL 5.7和java 8之前。现在我把它改成了mySQL 8和java 8。代码没有任何变化。原因一定是什么?? 下面是日志:

    • 问题内容: 结合使用JPA和Hibernate,运行以下代码时出现异常。第一次运行它时,一切正常,数据已插入数据库中。第二次,当应更新数据时,它失败: boutiqueDao.persist()只需调用EntityManager.persist()方法。 这是我的精品班: 最后,我的堆栈跟踪: 我正在Tomcat 7.0.32服务器上运行Java 7.0.11。 任何的想法? 问题答案: 用于全新

    • 我使用注释将两个实体相互映射。一个实体是,第二个实体是。drivers实体已经插入了一行,该行后来会成为bookedBus实体(PK)的外部引用(FK)。下面是两个实体,setter和getter为简洁起见被跳过。 第一实体 第二实体 现在当我尝试保存到已预订的总线实体时,它会抛出以下异常 组织。springframework。刀。InvalidDataAccessApiUsageExceptio

    • 我有一个类通知,它包含一个对象MessengerData:

    • 问题内容: 我已经成功用hibernate写了我的第一个主要的孩子例子。几天后,我再次使用它并升级了一些库。不知道我做了什么,但是我再也无法使它运行了。有人可以帮助我找出返回以下错误消息的代码中的错误吗: hibernate映射: 编辑: InvoiceManager.java 发票.java InvoiceItem.java 编辑: 从客户端发送的JSON对象: 编辑: 一些详细信息: 我试图通