非法尝试将一个集合与两个打开的会话相关联-Dropwizard与Hibernate

时间:2018-09-17 20:26:27

标签: hibernate session jpa dropwizard

我在dropwizard应用程序中使用Hibernate和JPA来帮助对象的CRUD操作。这是引发异常的方法

@RetryOnFailure(attempts = 5,
      types = {org.hibernate.exception.LockTimeoutException.class,
          org.hibernate.exception.LockAcquisitionException.class},
      delay = DATABASE_RETRY_DELAY_SECONDS, unit = TimeUnit.SECONDS)
  public MyObject createOrSave(MyObject myObject) {

    Session session = sessionFactory.openSession();



    session.beginTransaction();
    try {

      session.saveOrUpdate(service);
      session.getTransaction().commit();
    } catch (RuntimeException e) {

      session.getTransaction().rollback();
      throw e;
    } finally {

      if (session != null && session.isOpen()) {
        session.close();
      }
    }
    return myObject;
  }

SO上有很多线程可以解决这个问题,这是我到目前为止已经尝试过的事情

  • 检查会话是否打开,如果是,请使用session.getCurrentSession(),这会引发错误,提示“ transaction is already active
  • 完全不使用交易
  • 检查记录是否存在于数据库中,如果是,则使用session.merge()否则session.save()
  • 在我的人际关系中,请勿使用CascadeType.ALL,但这会导致出现“ trying to refernece transient object error

我没主意了,有主意吗?

进一步研究,看来问题出在与MyObject上声明为的元素集合的关系上

  @JsonIgnore
  @Column
  @ElementCollection(targetClass = Long.class)
  Set<Long> someLongIds;

还有其他方法可以声明它,以便在保存或更新myObject时对其进行修改吗?

所以我将映射更改为

      @JsonIgnore
      @Column
      @ElementCollection(targetClass = Long.class, fetch = fetchType.Lazy)
      Set<Long> someLongIds;

这摆脱了此特定映射的错误,但我仍然得到

Illegal attempt to associate a collection with two open sessions. Collection

该对象上所有其他映射的错误。

这是因为集合是Set吗?而不是线程安全的?

1 个答案:

答案 0 :(得分:0)

声音听起来像在Hibernate中有两个打开的Session,而MyObject正在从一个传递到另一个。

最简单的解决方案通常是使用相同的Session。如果使用JTA事务(或Hibernate中任何其他形式的contextual sessions),则可以通过调用sessionFactory.getCurrentSession()来找到。显然,这在多线程环境中是行不通的。

另一种方法是分离myObject。回到第一个会话(问题中未显示),当从数据库中检索myObject时,也可以将其与该会话分离:

session.detach(myObject);

这具有解决PersistentSet中的someLongIds的作用,因此可以在Session之外或在另一个Session中平等地访问它们。