为每个实体使用单独的 entitymanagerfactory 会导致问题吗?

Does using a seperate entitymanagerfactory for each entity cause problems?

我为每个实体类型创建了一个存储库 class(一个处理所有 jpa 方法的 class),它有自己的 entitymanagerfactory。 现在我在多对多关系中遇到了以下错误:

ValidationException [junit][EclipseLink-7251] Exception Description: The attribute [ID] of class [Person] is mapped to a primary key column in the database. Updates are not allowed.

这个错误在调试时通常不会再出现,而且似乎不会始终如一地出现,这让我相信这可能是管理器之间的同步问题。 (Pk 由 jpa 处理 - @Id @GeneratedValue - 我从未更改过,不过我确实使用级联合并)

我目前的假设是否正确,即拥有多个实体管理工厂是一个坏主意(并且可能与我的问题有关)?

EntityManagerFactory 表示一个持久单元或换句话说一个数据源。如果您没有多个数据源,则不应创建多个 EMF。不过,您可以创建多个 EntityManagers(您可以将其视为 'connections' 到数据库)。

你这样创建 EMF -

EntityManagerFactory emf = Persistence.createEntityManagerFactory(
  "objectdb://localhost/myDbFile.odb;user=admin;password=admin")

 EntityManagerFactory emf =
  Persistence.createEntityManagerFactory("myDbFile.odb");

然后你像这样创建 EntityManager -

 EntityManager em = emf.createEntityManager();

来自 Javadoc - http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManagerFactory.html

Interface used to interact with the entity manager factory for the persistence unit.When the application has finished using the entity manager factory, and/or at application shutdown, the application should close the entity manager factory. Once an EntityManagerFactory has been closed, all its entity managers are considered to be in the closed state.

添加更多,您可能还需要像这样创建的交易 -

try {
    em.getTransaction().begin();
    // Operations that modify the database should come here.
    em.getTransaction().commit();
  }
  finally {
    if (em.getTransaction().isActive())
      em.getTransaction().rollback();
  } 

我得出的结论是,不同的 EMF 实际上确实导致了单独的持久性上下文,这导致了诸如 validationException 之类的问题。

(我认为当同一实体的 2 个不同实例在 2 个不同的上下文中进行管理并且其中一个实例更改了它的状态时会发生这种情况,但我不确定)

这样测试的:

备注:

  • orderweek(=非拥有方)与 week 具有一对一的双向关系 cascadeType.ALL。
  • orderRep 和 weekRep 是执行与 Db 相关的 CRUD 语句的实例,每个都有自己的实体管理器,由它们自己的 EMF 创建
  • 2 个 EMF 是在单独的工厂中创建的 -类,但链接到相同的数据库并且应该使用相同的持久性单元 'BreadPU'。
  • 我后来意识到对同一个数据源使用多个 EMF 是个坏主意

(junit测试方法的相关部分)

OrderBill cheapOrder = new OrderBill(5, LocalDate.now());
weekRep.addWeek(cheapOrder.getOrderWeek());
//because of the cascade, both the cheapOrder and the week or now persisted in the DB and managed by weekRep

OrderBill dbOrder = orderRep.updateOrder(cheapOrder);
boolean t2 = weekRep.isManaged(cheapOrder); //true
boolean t3  = orderRep.isManaged(cheapOrder); //false
//It's because this returns false I assume both persistence contexts are different
boolean t4 =  orderRep.isManaged(dbOrder); //true
//If i now use "cheapOrder" to change the order i get the error
//If i now use "dbOrder" to change the order, db gets updated as expected