为什么不用APPLICATION SERVER呢?

解决方案 »

  1.   

    import java.io.*;
    import java.sql.*;
    import java.util.*;
    import java.util.Date;/**
    * 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接
    * 池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例.
    */
    public class DBConnectionManager {
      static private DBConnectionManager instance; // 唯一实例
      static private int clients;  private Vector drivers = new Vector();
      private PrintWriter log;
      private Hashtable pools = new Hashtable();  /**
      * 返回唯一实例.如果是第一次调用此方法,则创建实例
      *
      * @return DBConnectionManager 唯一实例
      */
      static synchronized public DBConnectionManager getInstance() {
        if (instance == null) {
          instance = new DBConnectionManager();
        }
        clients++;
        return instance;
      }  /**
      * 建构函数私有以防止其它对象创建本类实例
      */
      private DBConnectionManager() {
        init();
      }  /**
      * 将连接对象返回给由名字指定的连接池
      *
      * @param name 在属性文件中定义的连接池名字
      * @param con 连接对象
      */
      public void freeConnection(String name, Connection con) {
        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
        if (pool != null) {
          pool.freeConnection(con);
        }
      }  /**
      * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
      * 限制,则创建并返回新连接
      *
      * @param name 在属性文件中定义的连接池名字
      * @return Connection 可用连接或null
      */
      public Connection getConnection(String name) {
        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
        if (pool != null) {
          return pool.getConnection();
        }
        return null;
      }  /**
      * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
      * 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
      *
      * @param name 连接池名字
      * @param time 以毫秒计的等待时间
      * @return Connection 可用连接或null
      */
      public Connection getConnection(String name, long time) {
        DBConnectionPool pool = (DBConnectionPool) pools.get(name);
        if (pool != null) {
          return pool.getConnection(time);
        }
        return null;
      }  /**
      * 关闭所有连接,撤销驱动程序的注册
      */
      public synchronized void release() {
        // 等待直到最后一个客户程序调用
        if (--clients != 0) {
          return;
        }    Enumeration allPools = pools.elements();
        while (allPools.hasMoreElements()) {
          DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
          pool.release();
        }
        Enumeration allDrivers = drivers.elements();
        while (allDrivers.hasMoreElements()) {
          Driver driver = (Driver) allDrivers.nextElement();
          try {
            DriverManager.deregisterDriver(driver);
            log("撤销JDBC驱动程序 " + driver.getClass().getName()+"的注册");
          }
          catch (SQLException e) {
            log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
          }
        }
      }  /**
      * 根据指定属性创建连接池实例.
      *
      * @param props 连接池属性
      */
      private void createPools(Properties props) {
        Enumeration propNames = props.propertyNames();
        while (propNames.hasMoreElements()) {
          String name = (String) propNames.nextElement();
          if (name.endsWith(".url")) {
            String poolName = name.substring(0, name.lastIndexOf("."));
            String url = props.getProperty(poolName + ".url");
            if (url == null) {
              log("没有为连接池" + poolName + "指定URL");
              continue;
            }
            String user = props.getProperty(poolName + ".user");
            String password = props.getProperty(poolName + ".password");
            String maxconn = props.getProperty(poolName + ".maxconn", "0");
            int max;
            try {
              max = Integer.valueOf(maxconn).intValue();
            }
            catch (NumberFormatException e) {
              log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);
              max = 0;
            }
            DBConnectionPool pool =new DBConnectionPool(poolName, url, user, password, max);
            pools.put(poolName, pool);
            log("成功创建连接池" + poolName);
          }
        }
      }  /**
      * 读取属性完成初始化
      */
      private void init() {
        InputStream is = getClass().getResourceAsStream("/db.properties");
        Properties dbProps = new Properties();
        try {
          dbProps.load(is);
        }
        catch (Exception e) {
          System.err.println("不能读取属性文件. " +
          "请确保db.properties在CLASSPATH指定的路径中");
          return;
        }
        String logFile = dbProps.getProperty("logfile", "DBConnectionManager.log");
        try {
          log = new PrintWriter(new FileWriter(logFile, true), true);
        }
        catch (IOException e) {
          System.err.println("无法打开日志文件: " + logFile);
          log = new PrintWriter(System.err);
        }
        loadDrivers(dbProps);
        createPools(dbProps);
      }  /**
      * 装载和注册所有JDBC驱动程序
      *
      * @param props 属性
      */
      private void loadDrivers(Properties props) {
        String driverClasses = props.getProperty("drivers");
        StringTokenizer st = new StringTokenizer(driverClasses);
        while (st.hasMoreElements()) {
          String driverClassName = st.nextToken().trim();
          try {
            Driver driver = (Driver)Class.forName(driverClassName).newInstance();
            DriverManager.registerDriver(driver);
            drivers.addElement(driver);
            log("成功注册JDBC驱动程序" + driverClassName);
          }
          catch (Exception e) {
            log("无法注册JDBC驱动程序: " +
            driverClassName + ", 错误: " + e);
          }
        }
      }  /**
      * 将文本信息写入日志文件
      */
      private void log(String msg) {
        log.println(new Date() + ": " + msg);
      }  /**
      * 将文本信息与异常写入日志文件
      */
      private void log(Throwable e, String msg) {
        log.println(new Date() + ": " + msg);
        e.printStackTrace(log);
      }
      

  2.   

    /**
      * 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最
      * 大连接数为止.在返回连接给客户程序之前,它能够验证连接的有效性.
      */
      class DBConnectionPool {
        private int checkedOut;
        private Vector freeConnections = new Vector();
        private int maxConn;
        private String name;
        private String password;
        private String URL;
        private String user;    /**
        * 创建新的连接池
        *
        * @param name 连接池名字
        * @param URL 数据库的JDBC URL
        * @param user 数据库帐号,或 null
        * @param password 密码,或 null
        * @param maxConn 此连接池允许建立的最大连接数
        */
        public DBConnectionPool(String name, String URL, String user, String password,int maxConn) 
        {
          this.name = name;
          this.URL = URL;
          this.user = user;
          this.password = password;
          this.maxConn = maxConn;
        }    /**
        * 将不再使用的连接返回给连接池
        *
        * @param con 客户程序释放的连接
        */
        public synchronized void freeConnection(Connection con) {
          // 将指定连接加入到向量末尾
          freeConnections.addElement(con);
          checkedOut--;
          notifyAll();
        }    /**
        * 从连接池获得一个可用连接.如没有空闲的连接且当前连接数小于最大连接
        * 数限制,则创建新连接.如原来登记为可用的连接不再有效,则从向量删除之,
        * 然后递归调用自己以尝试新的可用连接.
        */
        public synchronized Connection getConnection() {
          Connection con = null;
          if (freeConnections.size() > 0) {
            // 获取向量中第一个可用连接
            con = (Connection) freeConnections.firstElement();
            freeConnections.removeElementAt(0);
            try {
              if (con.isClosed()) {
                log("从连接池" + name+"删除一个无效连接");
                // 递归调用自己,尝试再次获取可用连接
                con = getConnection();
              }
            }
            catch (SQLException e) {
              log("从连接池" + name+"删除一个无效连接");
              // 递归调用自己,尝试再次获取可用连接
              con = getConnection();
            }
          }
          else if (maxConn == 0 || checkedOut < maxConn) {
            con = newConnection();
          }
          if (con != null) {
            checkedOut++;
          }
          return con;
        }    /**
        * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间
        * 参见前一个getConnection()方法.
        *
        * @param timeout 以毫秒计的等待时间限制
        */
        public synchronized Connection getConnection(long timeout) {
          long startTime = new Date().getTime();
          Connection con;
          while ((con = getConnection()) == null) {
          try {
            wait(timeout);
          }
          catch (InterruptedException e) {}
            if ((new Date().getTime() - startTime) >= timeout) {
              // wait()返回的原因是超时
              return null;
            }
          }
          return con;
        }
       
        /**
        * 关闭所有连接
        */
        public synchronized void release() {
          Enumeration allConnections = freeConnections.elements();
          while (allConnections.hasMoreElements()) {
            Connection con = (Connection) allConnections.nextElement();
            try {
              con.close();
              log("关闭连接池" + name+"中的一个连接");
            }
            catch (SQLException e) {
              log(e, "无法关闭连接池" + name+"中的连接");
            }
          }
          freeConnections.removeAllElements();
        }
        
        /**
        * 创建新的连接
        */
        private Connection newConnection() {
          Connection con = null;
          try {
            if (user == null) {
              con = DriverManager.getConnection(URL);
            }
            else {
              con = DriverManager.getConnection(URL, user, password);
            }
            log("连接池" + name+"创建一个新的连接");
          }
          catch (SQLException e) {
            log(e, "无法创建下列URL的连接: " + URL);
            return null;
          }
          return con;
        }
      }
    }
      

  3.   

    to zhenyang2002(珍阳) ,
    如果没记错,这个东东就是两年前一个叫好兵的写的(当然不知他是否又是参考了别人),我现在就是用着这个东东,我还作了修改,且在每重要的一步都写入LOG,但就是没出发现池化的作用.
    outer2000(天外流星) ,
    商人都想着怎么多赚钱,软件的东西希望是能省就省的.现在用的是Tomcat!
      

  4.   

    不是的。这个例子源文来自www.wrox.com出的java服务器高级编程一书。
    我用的挺好,在处理多个数据库连接至大型数据库时效率明显提高。
    但我也有一个问题
    在InputStream is = getClass().getResourceAsStream("/db.properties");
    这句中db.properties文件只能放在classpath所指明的路径或当前路径下
    如果换成
    InputStream is = getClass().getResourceAsStream("/usr/local/etc/db.properties");
    的这样的绝对路径则不可以。
    哪位大侠试过放绝对路径怎么个用法?
      

  5.   

    to bluerain2002(蓝雨灰天) ,
    在使用DBConnectionManager 时,我试过当第一次连接正常后,断开WEB服务器网络连接,试打开WEB提示连不上DB,然后再接回来,再次打开WEB,则还是连不上DB,多次试也不行!(WEB服务器与DB服务器分离)
    你在BEAN里怎么调用DBConnectionManager 的实例?还是直接在JSP上调用?
    我写的BEAN大概是这样:
    ---------------------------------------------------
    public class MyBean{
      private Connection conn=null;
      private DBConnectionManager mgr;
      public MyBean() {
        mgr=DBConnectionManager.getInstance();
        conn=mgr.getConnection("test") ;
      }
      public synchronized Connection getConn(){
        try{
          if(conn==null || conn.isClosed()){
            conn=mgr.getConnection("test") ;
          }
        }catch(Exception e){
          conn=mgr.getConnection("test") ;
        }
        return conn;
      }
      public int executeUpdate(String sql){
        int intUpdate=0;
        try{
          Statement stmt=this.getConn().createStatement();
          intUpdate=stmt.executeUpdate(sql) ;
          stmt.close() ;
        }catch(Exception e){
          intUpdate=-1;
          System.out.println("Error from:["+sql+"]") ;
        }
        return intUpdate;
      }
    ......
      public void close(){
        mgr.freeConnection("test",conn) ;
      }
    }
    ---------------------------------------------------
    其他的BEAN中使用时:
    public class Test{
     public Test(){}
     public int update(){
       ...
       MyBean myBean=new MyBean();
       .....
       int intReturn=myBean.executeUpdate("....");
       myBean.close();
       return intReturn;
     }
     ....
    }
    JSP 中:
    <%
      Test test=new Test();
      out.print(""+test.update());
    %>-----------------
    一般大概是这样使用,请各位多多指教.
      

  6.   

    upc_chenli(chenli) ,
    用的是Tomcat4.0.3, Tomcat 自身能实现这个功能?
    具体应该如何设置?
    thanks.
      

  7.   

    我是在servlet里直接import connect.*
    代码基本与你写的一致,服务器为apache
    数据库也是与webserver分离的,我刚才试着拔掉网线。还好啊。。
      

  8.   

    怎么不用poolman呢??
    我觉得是一个不错的连接池
      

  9.   

    上述方法,已经不合适了,应该采用jsp/servlet + ejb + dao + Oracle,来设计。
      

  10.   

    你应该在第一次使用的时候就建立这个连接池,以后只从里面取一个连接就可以了,退出的时候关闭这个连接池(根据static private int clients这个来判断是否为最后一个客户程序调用,如果是就关闭)。
    我在用DBConnectionManager时加了下面一个方法,作用是得到这个连接池,但并不为这个连接池的客户数加一,这样总是保持同一时间只会建立一次连接池。在用户退出时才关闭连接池。
    static synchronized public DBConnectionManager getConnectionPool()
    {
    if(instance == null)
    {
    instance = getInstance();
    }
    return instance;
    }
      

  11.   

    http://jakarta.apache.org/tomcat/tomcat-4.0-doc/jndi-resources-howto.html
      

  12.   

    使用Oracle 的 JDBC 其中有对连接池的支持类!
      

  13.   

    core servlet and JSP这本书里有一个连接池的例子,也许可以参考一下:http://archive.coreservlets.com/Chapter18.html
      

  14.   

    告诉我你的邮箱,我给你发一份程序
    它是用xml来做配置文件的
    已经在一个网站项目中用过了,非常好用
      

  15.   

    我也是用上面的连接方式,WebServer用的是tomcat3.3.1,但我发现一个问题。就是当我进行多次不停的连接时,连接会出错,然后就再也连接不上了,当重起tomcat之后,又回复了正常。哪位大虾若是知道,请不吝赐教,谢了!
      

  16.   

    to: empirebb(帝国) ,
    我的信箱是:[email protected]
    谢谢
      

  17.   

    to  liusy_2001() ,
    我觉得源代码用到的:
    try {
              if (con.isClosed()) {
                log("从连接池" + name+"删除一个无效连接");
                // 递归调用自己,尝试再次获取可用连接
                con = getConnection();
              }
            }
            catch (SQLException e) {....}
    这段有问题.
    我查看了Oracle 的classes12.zip里的.....,
    .isClosed()方法是很简单,没理解错就是:当原来con有效时,如果没人用con.close(),则永远isClosed()=false!即是说如果中间由于网络断了,
    isClosed()还是false!连接还是有效?!
    我的办法是另写方法:
        private boolean isClosed(Connection con) throws SQLException{
          if(con==null) return true;
          Statement stmt=con.createStatement() ;
          stmt.close() ;
          return false;
        }
    改写上一段代码为:
    try {
      if (isClosed(con)){ //old: if(con.isClosed()) {
       // 递归调用自己,尝试再次获取可用连接
       con = getConnection();
      }
    }catch (SQLException e) {.....}
      

  18.   

    不错呀、、我也遇到一个问题。我是个JAVA的初学者、
    有谁知道在WINDOWS XP英文版下怎么改变它的变量路径呀!!
    希望高手指点!!!发我的信箱也可以回铁也可以我的信箱是[email protected]
      

  19.   

    直接用J2EE ApplicationServer上的DataSource不就完了吗,要省钱那就用JDBC2.0可选包里的DataSource,下载数据库驱动,比如Oracle的JDBC驱动就有DataSource和连接池。
      

  20.   

    用tomcat可以配置连接池,在server.xml中有例子:
    如:
      <Context path="/demo" docBase="mypath" debug="0" reloadable="true">
             <Resource name="jdbc/mydb" auth="SERVLET"
                        type="javax.sql.DataSource"/>
             <ResourceParams name="jdbc/mydb">
                <parameter><name>user</name><value>myuser</value></parameter>
    <parameter><name>password</name><value>mypasswd</value></parameter>
                <parameter><name>driverClassName</name>
           <value>oracle.jdbc.driver.OracleDriver</value></parameter>
                <parameter><name>driverName</name>
    <value>jdbc:oracle:thin:@mydbserver:1521:mydbsid</value></parameter>我在用jdbc-odbc桥方式时也出数据库错误,用了一段时间就报连接错误;
    用thin方式后没出过该毛病,
    tomcat版本4.0.1
      

  21.   

    对了,我用Tomcat4.03的JNDI连接池的时候,一般访问不会出现错误。但我作
    告负载的压力测试的时候,就会出现不知为什么,程序中的con.close()应该是将当前连接归还到连接池呀,不可能手工关闭物理连接的。
      

  22.   

    to:lbluekey(蓝鸟) 
    对这个东西con.close()我也有疑问,这样好象是关闭了实际连接,要用类似如datasource.close(con)方式关闭可能才用到连接池。哪位已经知道的或者有时间的摸索一把给个解释吧
      

  23.   

    con.close()本来就是关闭实际的连接
      

  24.   

    poolman不仅可以是数据库连接池,也可以做其他资源的缓冲池。
    多看看它的文档,会对数据库连接池有跟进一步的了解。对于大数据量测试,连接池就死掉,应该使用orion做服务器,监控数据连接释放情况。等真正体会了连接的创建和释放后再转为tomcat或其他。tomcat4里面多了tyrex-0.9.7.0.jar,如果看看官方文档,就会发现在tomcat3.X时,这是个第三方的数据库连接池包。所以,建议使用现有的比较成熟的数据库连接池产品。不反对好学者自己研究研究。
      

  25.   

    一个循环显示和记录集相关的问题?
    你们好救救我吧,我做了一个jsp程序是用来提问和回答的用了两个记录集
    为什么开始不出错要反复显示当前页面就出现下面的错误,两台机器一起运行出错更快,我用了一个嵌套两个while语句上层是显示问题下层显示对应的答案就出问题开始好的后来就不行了我的纪录集都关了,而别的页面一层循环是不会出错的,为什么,救救我,很急!!!!!!!!!!!后台显示的是这样的
    每次都是这个错误这是一样的下面不一定,是变地aq.executeQuery: ORA-00020: maximum number of processes (59) exceeded
    <2002/09/06 10:24:59:JST> <Error> <HTTP> <[WebAppServletContext(401473,DefaultWe
    bApp,/DefaultWebApp)] サーブレットは Exception により失敗しました。
    java.lang.NullPointerException
            at jsp_servlet._qa._jspService(_qa.java:482)
            at weblogic.servlet.jsp.JspBase.service(JspBase.java:27)
            at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubIm
    pl.java:263)
            at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubIm
    pl.java:200)
            at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppSe
    rvletContext.java:2390)
            at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestIm
    pl.java:1959)
            at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:137)
            at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:120)我的程序流程如下:
    ResultSet sqlRst= null;
    ResultSet answer = null;
    int pageSize = 10;
    int j=0;while(j<pageSize && !sqlRst.isAfterLast())
     {
    sqlanswer="select * from answer where answer_question_id='" + question_id + "' ";
    answer=QuestionsBean.executeQuery(sqlanswer); if (answer.next())
    {
    ......
    ......

    while(!answer.isAfterLast())
    {
    ......
    ......
    answer.next();
    }

    answer.close();
    answer = null;
    }

    else
        {
    answer.close();
    answer = null;
    } sqlRst.next();
     j++;
     }
     sqlRst.close();
     sqlRst=null;
      

  26.   

    aq.executeQuery: ORA-00020: maximum number of processes (59) exceeded
    不看你的代码,就看看你的这个错误信息就很明显——资源、资源,没有释放!
    上面是不是ASP或其他语言的写法,不要紧慢慢来,多看书,看好书~!
      

  27.   

    有关数据库连接池的问题已经解决,总的说来自己写处理连接池的类比较麻烦且性能也跟不上,最后的方案是使用DataSource编程,连接池的实现在WEB服务器中自带,如Oracle9iAS,WebLogic,Tomcat4.X.X等.有需要的IT人可联系我.由于近来比较忙没有结帖,现为了支持CSDN的强制结贴行动,由我开始.