EclipseLink惰性属性抛出ConcurrencyException

时间:2019-04-24 04:31:01

标签: jpa eclipselink

我有以下架构(简化和名称更改):

@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专家的帮助。谢谢!

0 个答案:

没有答案