我在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吗?而不是线程安全的?
答案 0 :(得分:0)
声音听起来像在Hibernate中有两个打开的Session,而MyObject正在从一个传递到另一个。
最简单的解决方案通常是使用相同的Session
。如果使用JTA事务(或Hibernate中任何其他形式的contextual sessions),则可以通过调用sessionFactory.getCurrentSession()
来找到。显然,这在多线程环境中是行不通的。
另一种方法是分离myObject
。回到第一个会话(问题中未显示),当从数据库中检索myObject
时,也可以将其与该会话分离:
session.detach(myObject);
这具有解决PersistentSet
中的someLongIds
的作用,因此可以在Session之外或在另一个Session中平等地访问它们。