通过JPA(Websphere和DB2)引用表时,结果集已关闭错误

时间:2012-03-28 14:00:34

标签: jpa db2 websphere openjpa

我正在WebSphere 7上使用IBM的Open JPA实现,当我尝试引用@ManyToOne的对象并从DB2继续收到以下错误时,我遇到了问题:

com.ibm.db2.jcc.b.SqlException:[jcc] [t4] [10120] [10898] [3.50.152]无效操作:结果集已关闭。 ERRORCODE = -4470,SQLSTATE = null

我正在拔头发,为什么这不起作用,希望有人可以提供帮助。

以下是数据库模式的简化视图:

表格报告

record_id - integer - (主键 - 由DB2生成)

代理 - 整数非空(Dropdown表的外键)

表格下拉

record_id - integer - (主键 - 由DB2生成)

以下是报告的JPA实体,该实体引用了该机构

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="AGENCY")
private Dropdown agency;

以下是我运行命名查询以获取数据然后迭代结果集以打印报告ID和agnency的代码。每当调用report.getAgency()时,我都会从DB2获得“结果集已关闭”错误:

@SuppressWarnings("unchecked")
public List<Report> getOpenIncidentsForUser(String aceId) throws Exception
{
    List<Report> results = null;
    EntityManager em = getEntityManager();

    try
    {
        Query query = em.createNamedQuery("getOpenIncidentsForUser");
        query.setParameter(1, aceId);
        results = (List<Report>) query.getResultList();

        Iterator<Report> it = results.iterator();
        while(it.hasNext())
        {
            Report report = it.next();
            System.out.println("Report [" + report.getRecordId() + "] Agency: [" + report.getAgency() + "]");
        }
    }
    catch (Exception e)
    {
        log.fatal("Fatal error getting incidents for user", e);
        throw e;
    }
    finally
    {
        em.close();
    }

    return (List<Report>) results;
}

如果我没有引用getAgency方法,我可以打印出关于报告的任何其他内容而没有任何问题。它似乎只是对第二个表的引用。有什么想法吗?

3 个答案:

答案 0 :(得分:3)

我在回答原始评论时回答了这个问题,但意识到我从来没有将问题标记为已回答,所以我想正式做到这一点。

此处记录了此修复程序:https://www.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/tejb_jpatroubleshoot.html

最终修复结果是resulSetHoldability设置需要为1而不是2

对于XA数据源,您必须将downgradeHoldCursorsUnderXa设置为true,否则您可能会收到此消息的持久性异常:

An SQL OPEN for a held cursor was issued on a XA connection

答案 1 :(得分:1)

设置DB2 resultSetHoldability = 1仅在使用非XA数据源时才有效。如果你需要保留2PC,那么这不是一个解决方案。

我有这个确切的问题,最后通过围绕违规代码硬编码事务来解决它。这就是我所拥有的:

public class RequeueRuleList_back {

/*
 * Injected resources ...
 */
@Resource UserTransaction txn;
@PersistenceUnit EntityManagerFactory emf;

:

public List<RequeueRuleBean> getRequeueRules() {

    /* 
     * We need a hard transaction around this code even though it is just a query
     * otherwise we cannot use a DB2 XA datasource to do this:
     * 
     * com.ibm.db2.jcc.am.SqlException: [jcc][t4][10120][10898][3.63.75] Invalid operation: result set is closed. ERRORCODE=-4470, SQLSTATE=null
     */

    try {
        txn.begin();
    } catch (Exception e) {
        FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage("Error starting transaction: " + e.getMessage()));
        return null;
    }
    EntityManager em = emf.createEntityManager();

    :

    Query q = em.createQuery("SELECT rr FROM RequeueRule rr");

    // Do useful things ...

    em.close();
    try {
        txn.commit();
    } catch (Exception e) {
        FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage("Error committing transaction: " + e.getMessage()));
    }
    :
}

}

答案 2 :(得分:0)

如果您只是使用jdbc连接DB2而没有使用Hibernate等,那么您也会遇到此错误。因为在使用DB2 9.7的新JDBC版本中,许多函数你不应该支持new vesion,尽管在旧版本的jdbc上没有运行错误。

这些功能包括。 1:PreparedStatement 旧版

pt.executeUpdate(sql);

新版

pt.executeUpdate();

2:连接迭代

旧版本:

  try{      
    conn = ConnectionFactory.getConnection(ApplicationConstants.LOCAL_DATASOURCE_JNDI_NAME);
    sql="select role_id,role_sname,role_sdesc from db2admin.mng_roles "+sql_condition+" order by role_id asc";
    pt = conn.prepareStatement(sql.toString());
    System.out.println("sql ="+sql);
    rs = pt.executeQuery();
    while(rs.next()){
                i++;
                role_id=rs.getInt(1);
                role_sname=PubFunction.DoNull(rs.getString(2)).trim();
                role_sdesc=PubFunction.DoNull(rs.getString(3)).trim();
                role_right=PubFunction.DoNull(newright.getRightsbyRole(conn,role_id)).trim();}

新版

  try{      
    conn = ConnectionFactory.getConnection(ApplicationConstants.LOCAL_DATASOURCE_JNDI_NAME);
    sql="select role_id,role_sname,role_sdesc from db2admin.mng_roles "+sql_condition+" order by role_id asc";
    pt = conn.prepareStatement(sql.toString());
    System.out.println("sql ="+sql);
    rs = pt.executeQuery();
    while(rs.next()){
                i++;
                role_id=rs.getInt(1);
                role_sname=PubFunction.DoNull(rs.getString(2)).trim();
                role_sdesc=PubFunction.DoNull(rs.getString(3)).trim();
                role_right=PubFunction.DoNull(newright.getRightsbyRole(null,role_id)).trim();}