hibernate / jpa抱怨“级联期间刷新”

时间:2019-02-16 09:34:19

标签: java hibernate jpa flush

我的应用程序崩溃并出现以下错误:

org.hibernate.HibernateException: Flush during cascade is dangerous

除非休眠代表我这样做,否则我不会冲洗。

规格:

  • tomcat上的webapp
  • 用于持久性的hibernate / jpa(由应用程序管理 实体经理)

这是我的util类的代码,用于管理实体管理器:

private static EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("returnit");

private static EntityManager entityManager;

public static EntityManager getEntityManager(){

    return entityManager;
}

public static EntityManager initEntityManager(){
  if (emFactory == null) {
      emFactory = Persistence.createEntityManagerFactory( "returnit" );
  }

  entityManager = emFactory.createEntityManager();
  return entityManager;
}

这是触发错误的方法:

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response post(@HeaderParam(HttpHeaders.AUTHORIZATION) String authHeader, MasterCrossDock mcd) {

    EntityManager em = Utils.initEntityManager();
    em.getTransaction().begin();

    MasterCrossDockDAO.save(mcd);

    em.getTransaction().commit();
    em.close();

    return Response.ok(mcd.getId()).build();
}

public static void save(MasterCrossDock new_mcd) {  

    List<Receptacle> receptacles = new_mcd.getReceptacles();

    List<Long> ids = new ArrayList<Long>();

    for (Receptacle r: receptacles) {
        ids.add(r.getId());
    }

    new_mcd.getReceptacles().clear();

    EntityManager em = Utils.getEntityManager();

    new_mcd.getCountryDestination())

    em.createQuery("UPDATE receptacle r"
            + " SET r.masterCrossDock.id = :mcd_id"
            + " WHERE r.id IN :ids")
    .setParameter("ids", ids)
    .setParameter("mcd_id", new_mcd.getId())
    .executeUpdate();

    new_mcd.getEreturns());
}

我为什么会收到上述错误以及如何解决?

2 个答案:

答案 0 :(得分:1)

实体管理器不是线程安全的。在容器管理的事务中使用EntityManager很好,但是在这里您要同时管理EntityManager和事务。而且,实体管理器是静态的,因此您可以有效地重用它,以便从控制器那里获得不同的请求。传入呼叫将执行更新查询,该查询将调用刷新。

我注意到,在您的initEntityManager期间,您正在用新实例交换objectManager的静态实例。那另一个线程可能正在使用的旧引用呢?

执行以下操作:

  1. 完整删除您的方法initEntityManager
  2. 删除私有静态EntityManager实体管理器;
  3. 为您提供方法Utils.getEntityManager();创建一个新的EntityManager

另一种解决方案应该是使Spring或您的容器(如果您使用容器管理事务)。进行服务,使用@Transaction属性对其进行注释,并使Spring / Container在其中注入EntutyManager,或者仅使用spring-data存储库。

答案 1 :(得分:0)

flush的Hibernate实现调用EntityTransaction操作,在您的情况下,它可能是JdbcResourceLocalTransactionCoordinatorImpl上的commit

SessionImpl内部,这是引发HibernateException的原因。

private void doFlush() {
    checkTransactionNeeded();
    checkTransactionSynchStatus();

    try {
        if ( persistenceContext.getCascadeLevel() > 0 ) {
            throw new HibernateException( "Flush during cascade is dangerous" );
        }
    ...

也许,我说也许,其他一些线程抓住了Session对象,并在您的实体上进行操作。