我现在是同连接池来实现,然后自己定义了个方法 public java.util.ArrayList executeQuery(String sqlQueryStmt)
 
public boolean executeUpdate(String sqlQueryStmt) 做为统一接口,想把所有方法都改成 static的, 但是还没有试过。不过现在已经方便很多了。    userinfo = dbcon.executeQuery(“select * from user”);
java.util.HashMap user=new java.util.HashMap();
for (int i=0;i<userinfo.size();i++ ) {
user=(java.util.HashMap)userinfo.get(i);
%>
用户id<%=user.get("userid")%>
用户名字<%=(String)user.get("username")%>
说明<%=(String)user.get("rolecontent")%>这样操作起来方便多了。不过连接池不听的释放和断开连接,我不知道效率影响大不大。

解决方案 »

  1.   

    首先,你这个类能工作吗?
    我看够戗。
    最起码的,JDK API中对ResultSet 的说明是:当STATEMENT被CLOSE,那么该ResultSet对象也会被同时关闭。所以你的类,除非是在JDBC实现不符合JDK API规范的前提下才可能运行正常。
    还有,没有看到你关闭连接。
    其它的暂不作评论了,以免打击你,建议你多看些书吧。如果是针对ORACLE的,那么推荐你一本:《ORACLE JAVA程序设计》
    (红皮的,出了一个系列的书,书名我也不是很确定)再说点,任何优化都应该在可测试且知道真正瓶颈的前提下才好做的,
    不然做了不如不作。特别是对性能的优化,首先要做的是针对系统的准确测量,找到真正的性能瓶颈。
      

  2.   

    用连接池解决连接开销问题确定为只读的数据用Singleton类放内存,所有客户端共享用缓冲将频繁访问的数据放在内存关键是缓冲机制,jive论坛的缓冲就很棒,可以研究一下,有点像CMB由容器提供一些缓冲,共享。
      

  3.   

    还有,不能使用STATIC方法,因为有并发访问的问题存在。也最好不要使用STATEMENT,而是使用PREPAREDSTATEMENT,使用PREPAREDSTATEMENT至少在效率上要好些,如果考虑带参数的SQL语句执行以及批处理的话,好的不是一丁点。
    至少ORACLE是这样。(JDBC的实现其实是关键,所以对不同数据库应该是有区别的)
      

  4.   

    swinging(山不在高) :
    谢谢您的回复!
    首先说明,这里的代码只是部分代码。然后说明一下,这个类工作正常。
    我贴一下这个类的完整代码,大家再帮忙看看,谢谢!
    package com.strong.data;import java.io.*;
    import java.sql.*;
    import java.util.Vector;
    import java.io.*;
    import com.strong.utils.*;/**
     * <p>Title: 数据库操作类</p>
     * <p>Description: 数据库操作函数</p>
     * <p>Copyright: Copyright (c) 2003</p>
     * <p>Company: 江西思创数码科技公司</p>
     * @author 姜晓东
     * @version 1.0
     */
    public class DataOpt {
      /*** 私有变量声明 ***/
      private ResultSet resultSet=null;
      private Statement statement=null;
      private Connection conn=null;
      //----------------------------------------------------------------------
      /**
       * 在构造函数中连接数据库
       * @param dbType  数据库类型
       * @param userId  用户名
       * @param userPwd 口令
       */
      public DataOpt() {
        try {
          conn = ConnectionManager.getConnection();
          ConnectionManager.getStats();
        }
        catch (Exception ex) {
          System.err.println("不能连接数据库!" + ex.getMessage());
        }
      }  //----------------------------------------------------------------------
      /**
       * 执行返回记录集的查询
       * @param sqlString SQL查询字符串
       * @return 返回ResultSet对象
       */
      public ResultSet executeQuery(String sqlString) {
        statement = null;
        resultSet = null;
        try {
          statement = conn.createStatement();
          resultSet = statement.executeQuery(sqlString);
        }
        catch (SQLException ex) {
          System.err.println("executeQuery()出错:" + ex.getMessage());
        }
        finally{
          try {
            if (statement != null) {
              statement.close();
              statement=null;
            }
          }
          catch (SQLException ex1) {
            System.err.println("executeQuery() error!");
          }
        }
        return resultSet;
      }  //----------------------------------------------------------------------
      /**
       * 执行插入、更新、删除查询
       * @param sqlString
       */
      public void executeUpdate(String sqlString) {
        statement = null;
        try {
          statement = conn.createStatement();
          statement.executeUpdate(sqlString);
        }
        catch (SQLException ex) {
          System.err.println("executeUpdate()出错" + ex.getMessage());
        }
        finally{
          try {
            if (statement != null) {
              statement.close();
              statement=null;
            }
          }
          catch (SQLException ex1) {
            System.err.print("DataOpt.executeUpdate() error!\n"+ex1.getMessage());
          }
        }
      }  /**
       * 向CLOB写入数据
       * @param querySql      CLOB字段插入empty_clob()
       * @param tableName
       * @param keyId
       * @param clobField
       * @param validateField
       * @param validateValue
       * @throws SQLException
       * @throws IOException
       */
      public void setClob(String querySql, String tableName, String keyId,
                          String clobField, String clobData, String validateField,
                          String validateValue) throws SQLException, IOException {
        try {
          resultSet = null;
          conn.setAutoCommit(false);
          this.executeUpdate(querySql); //执行插入操作,CLOB字段插入empty_clob()      resultSet = this.executeQuery("SELECT " + keyId + " FROM " + tableName +
                                        " WHERE " + validateField + "='" +
                                        validateValue + "'");
          int curId = (resultSet.next()) ? resultSet.getInt(keyId) : 1;      resultSet = this.executeQuery("SELECT " + clobField + " FROM " +
                                        tableName + " WHERE " + keyId + "=" + curId +
                                        " FOR UPDATE");
          oracle.sql.CLOB clobText = null;
          clobText = (resultSet.next()) ?
              (oracle.sql.CLOB) resultSet.getClob(clobField) : null;
          Writer writer = clobText.getCharacterOutputStream();
          writer.write(clobData);
          writer.flush();
          writer.close();
          conn.commit();
        }
        catch (SQLException ex) {
          System.out.println(ex.getMessage());
        }
        finally {
          try {
            resultSet.close();
          }
          catch (Exception ex) {
            System.out.println(ex.getMessage());
          }
          conn.setAutoCommit(true);
        }
      }  /**
       * 读取CLOB字段数据
       * @param tableName
       * @param keyId
       * @param clobField
       * @param opId
       * @return
       */
      public String getClob(String tableName, String keyId, String clobField,
                            String opId) {
        String returnString = "";
        try {
          StringBuffer querySql = new StringBuffer();
          querySql.append( "SELECT " ).append( clobField ).append( " FROM " ).append( tableName ).append( " WHERE ") .append(
              keyId ).append( "=" ).append( opId);
          resultSet = this.executeQuery(querySql.toString());
          if (resultSet.next()) {
            oracle.jdbc.driver.OracleResultSet oracleResultSet =
                (oracle.jdbc.driver.OracleResultSet) resultSet;
            oracle.sql.CLOB clob = (oracle.sql.CLOB) oracleResultSet.getClob(1);        if (! (clob == null || clob.length() == 0)) {
              returnString = clob.getSubString( (long) 1, (int) clob.length());
              returnString = StringKit.unFilterHTML(returnString);
            }
          }
        }
        catch (SQLException ex) {
          System.out.println(ex.getMessage());
        }
        finally{
          try{
            resultSet.close();
          }catch(SQLException ex){}
        }
        return returnString;
      }  /**
       * 执行存储过程
       * @param procName
       * @param params
       */
      public void execProc(String procName, String params) {
        //构造命令字符串///////////////////////////////////////
        String tmp[] = params.split(",");
        StringBuffer cmd = new StringBuffer();
        StringBuffer tmp2 = new StringBuffer();
        StringBuffer tmp3 = new StringBuffer(); //类型
        //String tmp3 = ""; //值
        cmd.append("{call " + procName + "(");    for (int i = 0; i < tmp.length; i++) {
          cmd .append( "?,");
          /////////////////////////////////////////
          String[] tmp1 = tmp[i].split("#");
          tmp2 .append( tmp1[0] ).append( ",");
          tmp3 .append( tmp1[1] ).append( ",");
        }
        cmd.substring(0, cmd.length() - 1);
        cmd .append( ")}");
        tmp2.toString().substring(0, tmp2.length() - 1);
        tmp3.toString().substring(0, tmp3.length() - 1);
        /////////////////////////////////////////////
        String[] _tmp2 = tmp2.toString().split(","); //拆分为数组
        String[] _tmp3 = tmp3.toString().split(",");
        CallableStatement cstmt = null;
        try {
          cstmt = conn.prepareCall(cmd.toString());
          for (int i = 0; i < _tmp2.length; i++) {
            if (_tmp2[i].equals("int")) {
              cstmt.setInt(i + 1, Integer.parseInt(_tmp3[i]));
            }
            else if (_tmp2[i].equals("var")) {
              cstmt.setString(i + 1, _tmp3[i]);
            }
          }
          cstmt.execute();
          cstmt.close();
        }
        catch (SQLException ex) {}
        catch (NumberFormatException ex) {}
      }  //----------------------------------------------------------------------
      /**
       * 清理对象
       * @throws SQLException
       */
      public void dispose() {
        try {
          ConnectionManager.returnConnection(conn);
          /*System.out.println("成功关闭Statement对象并归还数据库连接!连接数:" +
                             ConnectionManager.getInstanceNum());*/
          ConnectionManager.getStats();
        }
        catch (SQLException ex) {
          System.err.println("连接池错误!" + ex.getMessage());
        }
      }
    }
      

  5.   

    1.你的方法都不是线程安全的,在多线程下容易爆发空指针异常。2.可以用单例模式来设计你的数据访问类,以确保任何地方调用只有一个实例。public class DataOpt {
        
        private static DataOpt instance = null;    private DataOpt(){
            ...
        }    public static DataOpt getIntance(){
            if (instance == null){
                instance = new DataOpt();
            }
            return instance();
        }
      
        ...}
      

  6.   

    songbo_pp(皮皮) :
     您好!
     非常感谢您的回复!
     
     希望大家讨论一下这里能不能、该不该使用单例模式?谢谢!
      

  7.   

    这样做是不恰当的。除非有单一实例的需求,不然不要使用单例模式。在这里
    Connection 对象可以同时有几个实例共存,不需要是单一实例。
      

  8.   

    zenzuguocsdn(软虫):
    晕!您引述的是《JAVA与模式》P228页内容(附后),能否按您的理解进行说明呢?附:
    例子二
    问:我的一个系统需要管理与数据库的连接。学习了单例模式后,我发现可以使用一
    个单例类包装一个Connection 对象,并在finalize()方法中关闭这个Connection 对象。这样
    的话,在这个单例类的实例没有被人引用时,这个finalize()对象就会被调用,因此,
    Connection 对象就会被释放。这多妙啊。
    答:这样做是不恰当的。除非有单一实例的需求,不然不要使用单例模式。在这里
    Connection 对象可以同时有几个实例共存,不需要是单一实例。
    单例模式有很多的错误使用案例都与此例子相似,它们都是试图使用单例模式管理共
    享资源的生命周期,这是不恰当的。
      

  9.   

    重新实例化这个类不是问题,问题是建立连接时的开销,建议使用DataSource,而且最好是pool的,将DataSource放在服务器的环境中,让服务器来维护
      

  10.   

    caeserwliu(白云) :
    是的!建立连接以及执行executeQuery需要很大的系统开销,请问DataSouce能带来什么好处呢?
      

  11.   

    to 楼主,不是我说你,
    整个类我没有看到CLOSE   CONNECTION的语句,
    单凭这一点,
    这个类就没有价值。具体就不细讲了,可以看下这个帖子的讨论:
    http://expert.csdn.net/Expert/topic/2336/2336848.xml?temp=.6394464
    里面有我的观点。
      

  12.   

    另外指出的是:每次操作数据库都要实例化这个类,是不是很浪费资源?
    这个问题,
    每次操作都实例化并不浪费资源,
    而且这是必须的,因为有并发访问存在。你知道访问数据库中最大的资源是什么吗?是数据库连接,connection
    你不关闭连接,才是真正的资源浪费,你指望垃圾收集帮你收集?
    那是不可能的,先不说垃圾收集什么时候开始不确定,就是收集了,也不能替你关闭连接。
    如果你使用finalize()方法来关闭,结果是一样的,
    因为垃圾收集并不是那么及时的,所以放在finalize()中只能说比你完全不CLOSE好那么一点,不过也就半斤八两。
      

  13.   

    to  swinging(山不在高) 
    连接肯定是关闭了的,由于使用了连接池,你没看到这个类有个dispose方法么?里面就是将用完的Connection重新放进连接池的,如下:
    /**
       * 清理对象
       * @throws SQLException
       */
      public void dispose() {
        try {
          ConnectionManager.returnConnection(conn);
          /*System.out.println("成功关闭Statement对象并归还数据库连接!连接数:" +
                             ConnectionManager.getInstanceNum());*/
          ConnectionManager.getStats();
        }
        catch (SQLException ex) {
          System.err.println("连接池错误!" + ex.getMessage());
        }
      }
      

  14.   

    我改的别人的:  public java.util.ArrayList executeQuery(String sqlQueryStmt) {
        System.out.println("SQL String is " + sqlQueryStmt);
        java.util.ArrayList rows = new java.util.ArrayList();
        java.sql.Connection conn = null;
        java.sql.Statement stmt = null;
        java.sql.ResultSet rs = null;
        try {
          conn = this.getConnection(10000);
          stmt = conn.createStatement();
          rs = stmt.executeQuery(sqlQueryStmt);
          ResultSetMetaData rsmd = rs.getMetaData();
          int columnCount = rsmd.getColumnCount();
          while (rs.next()) {
            HashMap row = new HashMap();
            for (int i = 1; i <= columnCount; i++) {
              String cname = rsmd.getColumnName(i);
              row.put(cname, rs.getObject(i));
            }
            rows.add(row);
          }
          return rows;
        }
        catch (Exception e) {
          System.out.println("查询数据库出错,SQL语句为:" + sqlQueryStmt + "\n错误信息为:" +
                             e.getMessage());
          return null;
        }
        finally {
          try {
            rs.close();
            stmt.close();
            //关闭连接,返回连接
            this.freeConnection(conn);
            conn = null;
          }
          catch (Exception e) {
            System.out.println("释放连接出错,错误信息为:" + e.getMessage());
          //  return rows;
          }
        }
      }
      

  15.   

    采用连接池
    最好不要用JDBC-ODBC桥!
      

  16.   

    to  wellsoon(wellsoon) 
    请教:
    直接返回ResultSet和把结果存放至ArrayList再返回,后者有何优点呢?
      

  17.   

    唉,我还以为我眼睛出问题了。再次查找了下,你的public void dispose()方法没有在类中用到,
    我才想到你的关闭操作是在这个类外部操作的,
    如果是那样,那么你这个类只能算一个工具类,实现一些通用的操作方法而已,
    外部需要重新包装DAO。就你实现的共用的方法来说:
    第一、使用STATEMENT,效率很低,不是说编程效率,而是实际数据库访问对SQL的解析和执行,ORACLE的对SQL语句的执行机制决定了的,应该使用PREPAREDSTATEMENT,特别是带参数的语句,不论带的参数是int还是string还是其它什么的。(我只熟悉ORACLE,所以我也就ORACLE说,其它数据库不了解具体ORACLE执行SQL的过程说起来很长,就不细解释了)
    第二、看到的一个execProc(String procName, String params)方法使用参数传递,当时参数传递的方式很差,居然用一个STRING,然后在方法中分析STRING来处理,绝对是下下策。而且只支持STRING和INT的设置,还没有返回值,可用性很低,至少要有返回值处理,因为数据库端可能会有业务逻辑错误通过返回值返回,而具有返回操作结果记录的存储过程实在经常用。
    第三、异常都被CATCH了,而且有些还什么处理都不作,实在很糟糕这样做。
    第四、setClob方法,该方法不管三七二十一,就在处理完成后把AUTOCOMMIT设置为TRUE,
    如果外部正在进行事务处理怎么办?(这里,原来我以为你是准备在外部控制事务的,现在看来我的想法有点错误,估计对于事务,你会重新new出CONNECTION来处理)
    第五、一些小细节,比如在方法的开头有:
        statement = null;
        resultSet = null;
    这么做基本上没有什么意义,因为你在下面直接就又给相应变量重新赋值了,所以这么做没有必要,可以说完全是白做。最后,我还是不理解:
      public ResultSet executeQuery(String sqlString)
    这个方法真的可以返回一个可以使用的ResultSet吗?当然,看样子你早用过了,估计是可以,不过JDK API中对RESULTSET和STATEMENT的说明中,明确指出:
    When a Statement object is closed, its current ResultSet object, if one exists, is also closed. 
    不知道你用的是什么JDBC,你依赖的是具体JDBC的不规范实现,这样做感觉很不好。
      

  18.   

    非常感谢各位的关注,尤其是 swinging(山不在高) 朋友提出了很多中肯的意见(我已经给您发了短消息,不知收到否?),今天5:30前结贴!谢谢!
      

  19.   

    //直接返回ResultSet和把结果存放至ArrayList再返回,后者有何优点呢?swinging(山不在高) 也说了:When a Statement object is closed, its current ResultSet object, if one exists, is also closed. 所以除非在外部对数据读取处理了之后,才能够关闭数据库连接,
    引用swinging(山不在高)的话:“我才想到你的关闭操作是在这个类外部操作的,”这样操作起来也很不方便的。我是看 jdon上面一篇文章的例子是用的ArrayList的方式来返回,我在外部的操作使用非常方便,就可以完全不关心数据库里的查询函数的具体实现了,
    (请看看我顶楼的回复 )
    也完全不用去关心数据库的连接和断开连接的问题,外部的操作,仅仅只提交一个SQL语句,然后就可以在返回的ArrayList对得到的结果进行读取操作了。