关闭持久性管理器后如何使查询结果可用

Posted

技术标签:

【中文标题】关闭持久性管理器后如何使查询结果可用【英文标题】:How do you make query results available after closing the persistence manager 【发布时间】:2011-03-15 14:35:15 【问题描述】:

我正在学习 GAE,但有点卡住了。如果我使用以下内容,并使用 finally 来确保关闭持久性管理器,则在尝试实际读取 Note 对象时会出现异常:

public class Notes 
    public List<Note> getAll() 
    PersistenceManager pm = PMF.instance().getPersistenceManager();

    try 
        Query query = pm.newQuery("select from com.uptecs.google1.model.Note order by subject");
        return (List<Note>) query.execute();
     finally 
        pm.close();
    
    

我得到的例外是:

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)
    at org.datanucleus.store.query.Query.getFetchPlan(Query.java:497)

【问题讨论】:

【参考方案1】:

尝试使用detachable="true" 将对象从图表中分离出来:

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Note 
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long key;
...

注意:我完全理解这样做的必要性,有时您需要在控制器中检索对象和列表,关闭控制器中的 PM,然后将模型传递给视图。在我知道更好的解决方案之前,这就是我在 JDO/GAE 上所做的事情,到目前为止没有任何问题。

列表:

在我看来,如果您希望能够在 PM 关闭后使用列表中的所有项目,您将不得不分离它们。我会用它来获取特定的项目列表。一个完整的getAll() 可以很大。

public List<Note> getList()
    List<Note> detachedList=null, list=null;
    try 
        String query = "select from " + Note.class.getName();
        pm = PMF.get().getPersistenceManager();
        list = (List<Note>)pm.newQuery(query).execute();            
        detachedList = new ArrayList<Note>();
        for(Note obj : list)
            detachedList.add(pm.detachCopy(obj));
        

     finally 
        pm.close();
    
    return detachedList;


按键:

public Note findByKey(Long key) 
    Note detachedCopy=null, object=null;
    try
        pm= PMF.get().getPersistenceManager();
        object = pm.getObjectById(Note.class,key);
        detachedCopy = pm.detachCopy(object);
    catch (JDOObjectNotFoundException e) 
        return null; // or whatever
     
    finally 
        pm.close(); // close here
    
    return detachedCopy;


收盘后,您有一个分离的副本,您可以使用它。

参考:http://www.datanucleus.org/products/accessplatform_1_1/jdo/attach_detach.html

【讨论】:

我了解这部分,我不明白的是它是一个列表。我应该遍历整个列表并分离每个项目吗? 是的,我就是这样做的。我无法让它分离列表,当我尝试这样做时,我得到一个org.datanucleus.jdo.exceptions.ClassNotPersistenceCapableException:类“类“org.datanucleus.store.appengine.query.StreamingQueryResult”是不可持久的。似乎这就是什么如果您想分离各个项目并关闭 PM,则需要完成。【参考方案2】:

当结果在列表中返回时 - 对象被延迟检索(仅当您请求它们时)。由于您的持久性管理器已关闭,因此您会遇到异常。通过“分离”对象,您实际上是在告诉持久性管理器急切地检索它们。

【讨论】:

【参考方案3】:

除了来自 bakkal 的回答,我想说你绝对需要 detachable="true" 注释参数,否则你永远不会让它工作。 要分离对象列表,您还可以使用pm.detachCopyAll(your_query_result_list),这将比您实现分离的迭代快一点,并且可以让您节省几行代码。感谢JDO! ;-) 但请注意,此方法需要对其结果进行显式转换。

这是我目前在上一个应用程序中使用的一个工作示例(查询中使用的键是编码字符串):

pm = PMF.get().getPersistenceManager();

Query query = pm.newQuery(TandemSubscription.class);
query.setFilter("groupSubscriptionKey==groupSubscriptionKeyParam");
query.setOrdering("dateRDV desc");
query.declareParameters("String groupSubscriptionKeyParam");

// Get Data
@SuppressWarnings("unchecked")          
List<TandemSubscription> savedSubscriptions = 
     (List<TandemSubscription>) query.execute(Key);

// Detach all objects in the list
savedSubscriptions = 
     (List<TandemSubscription>) pm.detachCopyAll(savedSubscriptions);

pm.close();

// Now you can use the list and its content.

我希望这会有所帮助。

【讨论】:

以上是关于关闭持久性管理器后如何使查询结果可用的主要内容,如果未能解决你的问题,请参考以下文章

关闭上下文管理器后保持适合文件的可访问性

进入linux的进程管理器后不知道怎么退出来

Java 使用布局管理器后怎样设置控件的大小。

WIN7资源管理器点击右键或新建文件夹时自动关闭

打开任务管理器后keyboard.add_hotkey停止工作

如何启动windows资源管理器