Google App Engine - org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed
Why does the code below result in org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed? The exception appears to be thrown at query.getResultList().
public final void removeUserTokens(final String username) {
final Query query = entityManager.createQuery(
"SELECT p FROM PersistentLogin p WHERE username = :username");
query.setParameter("username", username);
for (Object token : query.getResultList()) {
entityManager.remove(token);
}
}
Exception:
org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed
at org.datanucleus.ObjectManagerImpl.assertIsOpen(ObjectManagerImpl.java:3876)
at org.datanucleus.ObjectManagerImpl.getFetchPlan(ObjectManagerImpl.java:376)
at org.datanucleus.store.query.Query.getFetchPlan(Query.java:497)
at org.datanucleus.store.appengine.query.DatastoreQuery$6.apply(DatastoreQuery.java:611)
at org.datanucleus.store.appengine.query.DatastoreQuery$6.apply(DatastoreQuery.java:610)
at org.datanucleus.store.appengine.query.LazyResult.resolveNext(LazyResult.java:94)
at org.datanucleus.store.appengine.query.LazyResult$LazyAbstractListIterator.computeNext(LazyResult.java:215)
at org.datanucleus.store.appengine.query.AbstractIterator.tryToComputeNext(AbstractIterator.java:132)
at org.datanucleus.store.appengine.query.AbstractIterator.hasNext(AbstractIterator.java:127)
at org.datanucleus.store.appengine.query.LazyResult$AbstractListIterator.hasNext(LazyResult.java:169)
at com.mystuff.service.auth.PersistentTokenRepositoryImpl.removeUserTokens(PersistentTokenRepositoryImpl.java:90)
Edit: I increased the log level for datanucleus and this is what I see.
FINE: Object Manager "org.datanucleus.ObjectManagerImpl@5d8d3d6c" opened for datastore "org.datanucleus.store.appengine.DatastoreManager@2447e380"
Feb 25, 2010 7:21:38 AM org.datanucleus.ObjectManagerImpl initialiseLevel1Cache
FINE: Level 1 Cac开发者_如何学Pythonhe of type "weak" initialised
Feb 25, 2010 7:21:38 AM org.datanucleus.JDOClassLoaderResolver classForName
FINE: Class "java.lang.PersistentLogin" was not found in the CLASSPATH [Class resolver called from org.datanucleus.util.Imports.resolveClassDeclaration (line=177)]
Feb 25, 2010 7:21:38 AM org.datanucleus.ObjectManagerImpl disconnectSMCache
FINE: Level 1 Cache cleared
Feb 25, 2010 7:21:38 AM org.datanucleus.ObjectManagerImpl postClose
FINE: Object Manager "org.datanucleus.ObjectManagerImpl@5d8d3d6c" closed
Feb 25, 2010 7:21:38 AM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: /j_spring_security_logout
Object Manager has been closed
org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed
at org.datanucleus.ObjectManagerImpl.assertIsOpen(ObjectManagerImpl.java:3876)
at org.datanucleus.ObjectManagerImpl.getFetchPlan(ObjectManagerImpl.java:376)
Adding @Transactional
to the method prevents the object manager from closing. However, I'm not sure why it closes without this.
I don't know why exactly, but it seems to have to do with query.getResultList()
being lazy-loaded. Apparently the lazy-loading breaks down when you call remove(token)
.
As a work-around can you collect the ids/keys for the elements in an ArrayList first, and in a separate loop remove them from the datastore?
the solution that worked for me and a description of the bug i found here:
http://groups.google.com/group/google-appengine-java/browse_thread/thread/945f6ca66c1c587e
精彩评论