论坛首页 Java企业应用论坛

ibatis 3.0 只创建不回收的BUG

浏览 3184 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-11-10   最后修改:2009-11-10
前两天刚解决了 IBatis.NET,不要相信它,内存疯狂泄漏 的bug....决定立即升级到最近版本 3.0.
结果今天又见一个BUG.:程序运行几分钟后,出现错误(oracle):打开游标数超过最大值
很明显,打开太多的Statement而没有关闭,不多说直接看源码(本人对于这种清理不干净的问题极其过敏)

一、问题
系统运行一段时间后,报(oracle):打开游标数超过最大值
二、原因BATCH模式的executor对所有select操作产生的Statement未执行close操作
SIMPLE的CRUD不存在此问题,但BATCH的所有select操作均未close。看三个关健方法代码:
// BatchExecutor.java 文件
  public int doUpdate(MappedStatement ms, Object parameterObject)
      throws SQLException {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null);
    BoundSql boundSql = handler.getBoundSql();
    String sql = boundSql.getSql();
    Statement stmt;
    if (currentSql != null && sql.hashCode() == currentSql.hashCode() && sql.length() == currentSql.length()) {
      int last = statementList.size() - 1;
      // 添加 statement
      stmt = statementList.get(last);
    } else {
      Connection connection = transaction.getConnection();
      stmt = handler.prepare(connection);
      currentSql = sql;
      statementList.add(stmt);
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
    handler.parameterize(stmt);
    handler.batch(stmt);
    return BATCH_UPDATE_RETURN_VALUE;
  }

  public List doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler)
      throws SQLException {
    flushStatements();
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, rowBounds, resultHandler);
    Connection connection = transaction.getConnection();
    Statement stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    try{  // 在这里添加两行代码,以close相关Statement
    return handler.query(stmt, resultHandler);
    }finally{ closeStatement(stmt); } //  add end.
  }

  // 这个方法在 commit 时会调用
  public List<BatchResult> doFlushStatements() throws SQLException {
    List<BatchResult> results = new ArrayList<BatchResult>();
    try {
      for (int i = 0, n = statementList.size(); i < n; i++) {
        Statement stmt = statementList.get(i);
        BatchResult batchResult = batchResultList.get(i);
        。。。。。省
        results.add(batchResult);
      }
      return results;
    } finally {
      for (Statement stmt : statementList) {
        // 在这里 close 批处理所用的 Statement
        closeStatement(stmt);
      }
      currentSql = null;
      statementList.clear();
      batchResultList.clear();
    }
  }


三.解决方法
上面代码已经给出相关说明。Batch模式对于更新操作会在commit时关闭,而 batch 模式对于select 操作是无效的,我们应该在做完select操作后直接将其close
   发表时间:2010-09-27  
你好,最近我读ibatis代码到此处,不是很明白doFlushStatements这个方法的用途,我发现只在BatchExecutor的query方法中调用了该方法,其他的executor类的query方法中没有对此调用,请告知?
0 请登录后投票
   发表时间:2010-09-27  
也许是你看错了。
BatchExecutor.query-->flashStatements-->doFlashStatements

BaseExecutor.commit-->flashStatements-->doFlashStatements
0 请登录后投票
   发表时间:2010-09-27  
嗯,我明白了。可是不解的是:ReuseExecutor.doQuery方法是否也要做同样的修改?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics