我有以下架构(简化和名称更改):
@Entity
@Table(name = "fubar")
@Inheritance(strategy = InheritanceType.JOINED)
public class Fubar {
@ManyToOne(fetch = FetchType.LAZY) // LAZY was recently added
@JoinColumn(name = "bar_id")
private Bar bar;
public Bar getBar() {
return bar;
}
}
@Entity
@Table(name = "foo")
public class Foo extends Fubar {
// Columns omitted for brevity
}
基本上,Foo
扩展了Fubar
,它具有延迟加载的Bar
属性。正如我在代码中的注释所指出的,FetchType.LAZY
是最近添加的。现在,当从数据库中检索到ConcurrencyException
记录后简单地调用getBar
方法时,便从EclipseLink中获得了Foo
。
@Named
@RequestScoped
public class FooBean {
@Inject
private FooDao fooDao;
@PostConstruct
public void initialize() {
long fooId = getSelectedFooId();
Foo foo = fooDao.findById(fooId);
foo.getBar(); // Boom! -> ConcurrencyException
}
}
这是FooDao
的简化版本。我们正在使用与another post中描述的EntityManagerHelper
非常相似(但不完全相同)的东西(实际上只是EnityManager
内部的ThreadLocal
)。为简单起见,我将在下面的代码中使用EntityManagerHelper
:
public class FooDao {
public Foo findById(long id) {
EntityManager em = EntityManagerHelper.getEntityManager();
List<Foo> foos = em
.createQuery("SELECT f FROM Foo f WHERE f.id = :id", Foo.class)
.setParameter("id", id)
.setMaxResults(1)
.getResultList();
return (foos.size() > 0) ? foos.get(0) : null;
}
}
最后但并非最不重要的是,这是我们从EclipseLink获得的堆栈跟踪:
org.eclipse.persistence.exceptions.ConcurrencyException:
Exception Description: A signal was attempted before wait() on ConcurrencyManager. This normally means that an attempt was made to
commit or rollback a transaction before it was started, or to rollback a transaction twice.
at org.eclipse.persistence.exceptions.ConcurrencyException.signalAttemptedBeforeWait(ConcurrencyException.java:84) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.helper.ConcurrencyManager.releaseReadLock(ConcurrencyManager.java:468) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.identitymaps.CacheKey.releaseReadLock(CacheKey.java:468) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1041) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:955) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(UnitOfWorkIdentityMapAccessor.java:209) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getFromIdentityMap(UnitOfWorkIdentityMapAccessor.java:137) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:3942) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.queries.ObjectBuildingQuery.registerIndividualResult(ObjectBuildingQuery.java:448) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.queries.ReadObjectQuery.registerResultInUnitOfWork(ReadObjectQuery.java:887) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkEarlyReturn(ObjectLevelReadQuery.java:880) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.mappings.OneToOneMapping.checkCacheForBatchKey(OneToOneMapping.java:835) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.mappings.ForeignReferenceMapping.extractResultFromBatchQuery(ForeignReferenceMapping.java:531) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.indirection.BatchValueHolder.instantiate(BatchValueHolder.java:58) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.indirection.QueryBasedValueHolder.instantiate(QueryBasedValueHolder.java:116) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:89) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:173) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:234) ~[org.eclipse.persistence.core.jar:na]
at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:89) ~[org.eclipse.persistence.core.jar:na]
at com.mycompany.model.Foo._persistence_get_bar(Foo.java)
at com.mycompany.model.Foo.getBar(Foo.java:16)
at com.mycompany.beans.FooBean.initialize(FooBean.java:20)
根据EclipseLink FAQ for resolving deadlocks,鼓励开发人员将所有关系设为LAZY。我们为什么现在得到ConcurrencyException
?在这方面,我需要EclipseLink专家的帮助。谢谢!