用连接池,在并发访问人数很多,频繁操作数据库时,这时候用连接池能提高效率.如果只是单个连接,那么DriverManager直连是比连接池要快.用不用连接池要根据你的实际情况来决定.

解决方案 »

  1.   

    用连接池,在并发访问人数很多,频繁操作数据库时,这时候用连接池能提高效率.我也是这么认为的,所以我在单机上这样模拟并发:
    package datago;
    import java.sql.*;
    import javax.sql.*;
    import javax.naming.*;
    import java.util.Properties;
    import javax.rmi.PortableRemoteObject;/**
     * <p>Title: </p>
     * <p>Description: </p>
     * <p>Copyright: Copyright (c) 2004</p>
     * <p>Company: </p>
     * @author thunder
     * @version 1.0
     */public class testPool extends Thread{
        DataSource ds=null;
        Context ctx=null;
        Connection conn=null;
        public testPool() {
            try{
                ctx=getInitialContext();
                ds=(DataSource)ctx.lookup("sqlDS");
            }catch(Exception e){
                System.out.println(e.getMessage());
            }
        }    public static Context getInitialContext()throws Exception{
            String url="t3://192.168.0.3:7001";
            String user="system";
            String password="11111111";
            Properties p=null;
            try{
                p=new Properties();
                p.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
                p.put(Context.PROVIDER_URL,url);
                if(user!=null){
                    p.put(Context.SECURITY_PRINCIPAL,user);
                    p.put(Context.SECURITY_CREDENTIALS,password==null?"":password);
                }
                return new InitialContext(p);
            }catch(Exception e){
                throw e;
            }
        }
        public void run(){
            String sql="select * from note";
            try{
                conn=ds.getConnection();
                PreparedStatement ps=conn.prepareStatement(sql);
                ResultSet rs= ps.executeQuery();
                while (rs.next()) {
                     System.out.println(rs.getString(1)+"  "+rs.getString(2)+"  "+
                     rs.getString(3)+"  "+rs.getString(4)+"  "+rs.getString(5)+"  "+
                     rs.getString(6)+"  "+rs.getString(7)+"  "+rs.getString(8)+"  "+
                     rs.getString(9)+"  "+rs.getString(10));
                 }
            }catch(Exception e){
                System.out.println(e.getMessage());
            }finally{
                try{
                    conn.close();
                }catch(Exception e){
                    System.out.println(e.getMessage());
                }        }
        }
        public static void main(String argv[]){
            Thread t[]=new Thread[100];
            for(int i=0;i<100;i++){
                t[i]=new testPool();
                t[i].start();
            }
            
        }
    }但是没有这样快
    package datago;
    import java.sql.*;/**
     * <p>Title: </p>
     * <p>Description: </p>
     * <p>Copyright: Copyright (c) 2004</p>
     * <p>Company: </p>
     * @author thunder
     * @version 1.0
     */public class testDirectConnection extends Thread{
        SqlObject so=null;  
        public testDirectConnection() {
            
            so=new SqlObject();
        }
        public void run(){
            try{
                PreparedStatement ps;
                ps=so.prepareStatement("select * from note");
                ResultSet rs=ps.executeQuery();
                while (rs.next()) {
                    System.out.println(rs.getString(1)+"  "+rs.getString(2)+"  "+
                    rs.getString(3)+"  "+rs.getString(4)+"  "+rs.getString(5)+"  "+
                    rs.getString(6)+"  "+rs.getString(7)+"  "+rs.getString(8)+"  "+
                    rs.getString(9)+"  "+rs.getString(10));
                }
            }catch(Exception e){
                System.out.println(e.getMessage());
            }finally{
                so.sqlclose();
            }
        }
        public static void main(String argv[]){
            Thread t[]=new Thread[100];
            for(int i=0;i<100;i++){
                t[i]= new testDirectConnection();
                t[i].start();
            }
        }
    }
      

  2.   

    不是高手,不過你的代碼有些問題,Context的初始化是要消耗不少資源的,請把的作爲static的情況,只初始化一次。另外,你的select語句是一個全表搜索,如果這個時間比較長,也會影響你的感覺。
      

  3.   

    两个都是用同样的查询语句阿。
    to:CoolAbu(阿卜-Never Stop(★★★★)) 
    用100个线程一起查,不算并发??
      

  4.   

    可以用WLS 或是JBOSS的连接池,自己写也可以的,网上这样的东东很多的,这样可以弹性的控制连接池的数目.当连接池不够用时,会自动的NEW一个出来,如果有空闲的连接,就可以分配给请求连接的人了.
    记住用完一次连接时要把它CLOSE 呀,不然DATEBASE 还是会死的.
      

  5.   

    to:wftree
    把conetext改称静态的是可以提高速度,我试过了。但是每个用户来访问数据库时不是都要去获取上下文吗。
    to:tanguangbin
    我就是用的wls的连接池阿,你说的那些我都注意到了,而且配置没有任何问题。我现在用了很多种方法,测的速度都是直连接快,洗完你们能给我指条路,什么情况下连接池比直连接快,单机写的程序是否可以测出来.
    谁能给个测出连接池速度比直连接速度快的代码,另外再开帖高分回报。
      

  6.   

    當然需要或得context,但是你不用每次都去初始化這個context。
    如果你每次都去初始化,和你每次都新建一個連接又有什麽去別?
      

  7.   

    你是不是通过
    testPool t1=new testPool()
    t1.start()
    这样来测试的? 你发觉没?如果这样,你没启动实例一个testPool,都要初始化Context你用另一种写法 public class testPool implement Runnable
    然后用
    testPool tp=new testPool();  Thread t1=new Thread(tp);
      t1.start();
      Thread t2=new Thread(tp);
      t2.start();下面的这种效率要高,你可以试试。
      

  8.   

    我现在用了很多种方法,测的速度都是直连接快******************************************************你说的直连接是不是不用连接池,直接连呀? 那有100一起连你要怎么办? 如果有很多的用户建立了连接,没有池管理你怎么再将它们分配给其它的人用? 一直的于数据库连接而不释放,你猜会怎么样?使用JDBC 和 JNDI 连接查找都是很费资源的,所以对于JDBC可以建立连接池,把可用的连接放在池中,这样你要访问数据库时就不用每次都去连了.对JNDI的查找可以用SERVICE LOCATOR 模式,将它放在MAP或是其它的对象中,这样只要查找一次就可以了.
      

  9.   

    这是我以前用的一个连接池:
    /**********************************************************************
     用法说明:
     使用时建议使用包含后使用实例的方法。而不是使用UseBean的方法。
     本程序支持事务操作。
     使用方法 executeCommit()或executeRollback()即结束一次事务处理。
     然后调用dbClose() 结束一次连接。
     事务过程由程序调用者控制,在使用时以上两种方法是必需的。
     程序提供的方法有: public dbAccess(boolean AC,String fn)
         构造方法,其中AC为是否自动提交,缺省为非自动提交。
             其中fn为使用该类的程序。 public ResultSet executeQueryRs(String sql)
          执行查询,参数为SQL语句,返回记录集型数据。 public executeUpdate(String sql)
         执行更新,参数为SQL语句,缺省为非自动提交。
         包括更新表内容
           成功返回更新的行数(整数)可能为0。
           SQL语句错误时,返回 -1
           新建、删除表及其他数据库定义操作。
           成功返回 0
           SQL语句错误时,返回 -1 public dbClose()
         关闭与数据库的连接 public boolen executeCommit() //提交
     public boolen executeRollback() //回滚 错误信息返回方法:
     getEx()  获取SQL例外,类型为 SQLException
     getErrMsg() 获取错误信息,类型为 String
     getErrCode() 获取错误代码,类型为 int
     ***********************************************************************/
    package dhcc.pdaUtil;import java.util.*;
    import java.sql.*;
    import java.lang.reflect.*;
    import javax.naming.*;
    import dhcc.*;public class dhccrmsqlBean {
      private Connection conn = null;
      private Statement stmt = null;
      private ResultSet rs = null;
      javax.sql.DataSource myDataSource = null;  private boolean AutoCommit;
      private String fileName = null;
      private SQLException Ex = null;
      private String ErrMsg = null;
      private String strsql = null;
      private int ErrCode = 0;  private wLog errLog = new wLog("error");  //缺省为非自动提交
      public dhccrmsqlBean() {
        AutoCommit = true;
        fileName = "unknown";
        conn = makeConnection();
      }  public dhccrmsqlBean(boolean AC) {
        AutoCommit = AC;
        fileName = "unknown";
        conn = makeConnection();
      }
      //打开对数据库的访问
      public boolean getConnStatue() {
        if (conn != null) {
          return true;
        }
        else {
          return false;
        }
      }   //建立数据库访问Connection
      public Connection makeConnection() {
        Ex = null;
        ErrMsg = null;
        ErrCode = 0;    try {
          //查找系统配置文件
          ResourceBundle rb = ResourceBundle.getBundle("dhcc.db");
          String dbjndi = rb.getString("dbjndi");      //建立数据库连接
          Context ctx = new InitialContext();
          myDataSource = (javax.sql.DataSource) ctx.lookup(dbjndi);
          conn = myDataSource.getConnection();
          conn.setAutoCommit(AutoCommit);
        }
        catch (java.lang.SecurityException e) {
            this.dbClose();
            return null;
        }
        catch (java.sql.SQLException e) {
          Ex = e;
          ErrMsg = e.getMessage();
          ErrCode = e.getErrorCode();
          this.dbClose();
           return null;
        }
        catch (Exception e) {
          this.dbClose();
          return null;
        }
        return conn;
      }
     //执行提交
      public boolean executeCommit() {
        Ex = null;
        ErrMsg = null;
        ErrCode = 0;
        boolean Successed = false;
        try {
          if (conn != null) {
            conn.commit();
            Successed = true;
            }
        }
        catch (SQLException e) {
          Ex = e;
          ErrMsg = e.getMessage();
          ErrCode = e.getErrorCode();
          this.dbClose();
        }    if (Ex != null) {
          errLog.writeLog("Program:  " + fileName +
                          "\r\n                       SQL:  commit" +
                          "                       SQLException:  " + Ex.toString() +
                          "\r\n");
          Successed = false;
        }
        return Successed;
      }  //执行回滚
      public boolean executeRollback() {
        Ex = null;
        ErrMsg = null;
        ErrCode = 0;
        boolean Successed = false;
        try {
          if (conn != null) {
            conn.rollback();
            Successed = true;      }
        }
        catch (SQLException e) {
          Ex = e;
          ErrMsg = e.getMessage();
          ErrCode = e.getErrorCode();
          this.dbClose();
        }    if (Ex != null) {
          errLog.writeLog("Program:  " + fileName +
                          "\r\n                       SQL:  rollback" +
                          "                       SQLException:  " + Ex.toString() +
                          "\r\n");
          Successed = false;
        }    return Successed;
      }
      //关闭对数据库的访问
      public boolean dbClose() {
        try {
          if (rs != null) {
           closeRs();
          }
          if (stmt != null) {
            closeStmt();
          }
          if (conn != null) {
             closeConn();
          }
          return true;
        }
        catch (Exception e) {
          errLog.writeLog("dbClose()  Exception:  " + e.toString());
          return false;
        }
      }  //返回SQL错误例外
      public SQLException getEx() {
        return Ex;
      }
      public ResultSet executeQuery(String sql) {
        ResultSet rs = null;
        try {
          if(conn != null) {
            stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                                ResultSet.CONCUR_READ_ONLY);
            rs = stmt.executeQuery(sql);
          }
        }
        catch (SQLException ex) {
          System.err.println("sql_data.executeQuery:" + ex.getMessage());
          this.dbClose();
        }
        return rs;
      }  public boolean executeUpdate(String sql) {
        try {
           if(conn != null) {
             stmt = conn.createStatement();
             stmt.executeUpdate(sql);
             return true;
           }
        }
        catch (SQLException ex) {
          System.err.println("aq.executeUpdate: " + ex.getMessage());
          this.dbClose();
          return false;
        }
        return false;
      }  //返回SQL错误代码
      public int getErrCode() {
        return ErrCode;
      }  public void closeStmt() {
        try {
          stmt.close();
          stmt = null;
        }
        catch (SQLException e) {
          e.printStackTrace();
        }
      }
      public void closeRs() {
          try {
            rs.close();
            rs = null;
          }
          catch (SQLException e) {
            e.printStackTrace();
          }
        }  public void closeConn() {
        try {
          conn.close();
          conn = null;
        }
        catch (SQLException e) {
          e.printStackTrace();
        }
      }}
      

  10.   

    连接池不一定比DriverManager直连快.
    但它可以减轻数据库的压力。利用有限的数据库常连接,对数据库操作进行
    排队。如果数据库操作瞬间很多,数据库真的会死掉的。
    连接池可以把最大连接数限制的可承受的的数量内。
    保证数据库的稳定。
      

  11.   

    刚刚也写了个连接池,不过没用JNDI,直接用Servlet的,不知有什么好方法直接测试它在多用户并发访问时的效率?另:放于数据库连接池中的同一个连接,可不可以同时给多个用户使用;即一个在空闲池中的连接分配给了一个用户后,在他还没还回到空闲池时(在使用池中)又将这一连接分配给第二个人使用,依次下去给多个用户,同时使用,这样会有什么问题吗?如果使用没问题,对效率有没提升或其他影响?
      

  12.   

    to :henry771885(henry771885)
    我在写有关java数据库方面的论文,在讨论连接池,测试程序的结果和你说的差不多,速度是采用连接池的比采用直连接的慢,但是采用连接池可以使数据库稳定运行,如果并发很大,用直连接会很快死掉。而用连接池没问题。另外就是Connection对象去调用close()函数,好像连接不会马上释放阿,同事今天试了试也是这样啊,难道Connection对象的关闭要等到gc来回收吗?
      

  13.   

    调用Connection对象的close()函数,好像是不能马上释放,但是那个Connection对象实例已经不能再用于连接了,估计是有pool自身的管理优化在内的吧,以便于建立下一个连接时候会快一些,和windows管理ftp connect原理差不多吧。
    PS: 没有证实过,就当是我说梦话好了。嘿嘿
      

  14.   

    嗬嗬,楼主,你肯定每次都用ds都是通过JNDI查找吧?其实整个程序生命周期中只要查找一次ds就可以了。这样,只是第一次用连接池的时候感觉会很慢,但以后就会很快了。
      

  15.   

    我想是在问为什么要用连接池,它的效率体现在哪,而不是如何实现
    这个要在你的项目投入运行后才能更好的体现,如果单单是自己做做,一个人访问,必然无从体现。而且在使用连接池时要注意连接的回收,不然会消耗内存
    看到过一篇文章,也许你看了后会明白为什么在很多人访问程序时,用连接池效率要高:每个对新数据库连接的请求都会导致很大的开销。如果频繁地获取新的连接,将会影响性能,这在 Web 服务器环境中可能会出现。为了强调为什么会发生这种情况,让我们来看看一个典型的数据库连接请求的底层途径。.Java 应用程序调用 getConnection()。
    .JDBC 厂商代码(驱动程序或者 DataSource 实现)请求一个来自 JVM 的套接字连接。
    .JVM 需要检查底层调用的安全方面。例如,applet 只被允许和产生它们的服务器进行通讯。
    .如果允许,调用需要穿过主机网络接口到公司 LAN 上。
    .调用可能需要穿过防火墙到达因特网或广域网。
    .调用最终到达目的子网络,在那里它可能需要穿过另一个防火墙。
    .调用到达数据库主机。
    .数据库服务器处理新的连接请求。
    .许可证服务器可能需要查询来确定是否有适当的许可。
    .数据库初始化新的客户机连接,包括所有内存和操作系统开销。
    .返回调用被送回 JDBC 客户机(在那里它必须穿过所有防火墙和路由器)。
    .JVM 收到返回调用,然后创建适当的 Connection 对象。
    .请求的 Java 应用程序收到 Connection 对象。 很明显,请求一个新的 Connection 对象会带来大量的开销和很多潜在的错误。为了最小化开销,为什么在我们使用完数据库连接后不是重新使用它们,而是删除它们呢?JDBC 设计者在创建 ConnectionPoolDataSource 时使用这种流行的设计模式,这允许您创建数据库连接池,其中的连接在关闭后可以重用,而不是被删除。 
      

  16.   

    to : vinep(vvv)
    首先非常感谢你参与,但是我需要的是实际的实验结果,理论上的东西我很清楚,我只是想通过实际的数字来证明。
    我已经按照CoolAbu(阿卜-Never Stop(★★★★)) 说的写了个类专门去获取DataSource;
    这样避免了反复去查上下文,但是测试结果还是直连接比池连接快了一倍。
    今天遇上一个大学的java教师,他说池连接的速度绝对不会比直连接快,只是池连接在并发访问上的稳定性远强于直连接,这和我这几天测的结果差不多。其实我的代码已经改了很多种了,只是不方便都贴在这里。
    我想我应该重新理解高效了,如果并发很多,你直连接再快,瞬间被搞死了,再没有连接可用了,还要重起服务器,我想这不能算高效把,虽然池连接的速度慢点,但是不容易被搞死,这就是稳定的高效吧。
    不知道你们同意我的观点不。还有,如果你们能提供数字,说明在建连接时确实池连接比直连接快,我愿洗耳恭听。