技术开发 频道

Servlet开发中JDBC的高级应用(下)

【IT168技术文档】

连结池使用实例
 
  单一的实例在第一次调用时创建,以后的调用返回该实例的静态应用。一个计数器纪录所有的客户数,直到客户释放引用。这个计数器在以后用来协调关闭连接池。
 
  一、初始化

  构造函数调用一个私有的init()函数初始化对象。

private void init() {  InputStream is = getClass().getResourceAsStream("/db.properties");  Properties dbProps = new Properties();  try {   dbProps.load(is);  }  catch (Exception e) {   System.err.println("Can not read the properties file. "
+ "Make sure db.properties is in the CLASSPATH");   return;  }  String logFile = dbProps.getProperty("logfile",     "DBConnectionManager.log");  try {   log = new PrintWriter(new FileWriter(logFile, true), true);  }  catch (IOException e) {   System.err.println("Can not open the log file: " + logFile);   log = new PrintWriter(System.err);  }  loadDrivers(dbProps);  createPools(dbProps); }
  方法getResourceAsStream()是一个标准方法,用来打开一个外部输入文件。文件的位置取决于类加载器,而标准的类加载器从classpath开始搜索。Db.properties文件是一个Porperties格式的文件,保存在连接池中定义的key-value对。下面一些常用的属性可以定义:
 
   drivers 以空格分开的JDBC驱动程序的列表
 
   logfile 日志文件的绝对路径
 
  每个连接池中还使用另一些属性。这些属性以连接池的名字开头:
 
   .url数据库的JDBC URL
 
   .maxconn最大连接数。0表示无限。
 
   .user连接池的用户名
 
   .password相关的密码
 
  url属性是必须的,其他属性可选。用户名和密码必须和所定义的数据库匹配。
 
  下面是Windows平台下的一个db.properties文件的例子。有一个InstantDB连接池和一个通过odbc连接的Access数据库的数据源,名字叫demo。
drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver logfile=D:\\user\\src\\Java\\DBConnectionManager\\log.txt idb.url=jdbc:idb:c:\\local\\javaWebserver1.1\\db\\db.prp idb.maxconn=2 access.url=jdbc:odbc:demo access.user=demo access.password=demopw
  注意,反斜线在windows平台下必须双写。
 
  初始化方法init()创建一个Porperties对象并装载db.properties文件,然后读取日志文件属性。如果日志文件没有命名,则使用缺省的名字DBConnectionManager.log在当前目录下创建。在此情况下,一个系统错误被纪录。
 
  方法loadDrivers()将指定的所有jdbc驱动程序注册,装载。
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("Registered JDBC driver " + driverClassName);   }   catch (Exception e) {    log("Can not register JDBC driver: " + driverClassName + ", Exception: " + e);   }  } }
  loadDrivers()使用StringTokenizer将dirvers属性分成单独的driver串,并将每个驱动程序装入java虚拟机。驱动程序的实例在JDBC 的DriverManager中注册,并加入一个私有的向量drivers中。向量drivers用来关闭和注销所有的驱动程序。
 
  然后,DBConnectionPool对象由私有方法createPools()创建。
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("No URL specified for " + poolName);     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("Invalid maxconn value " + maxconn + " for " + poolName);     max = 0;    }    DBConnectionPool pool = new DBConnectionPool (poolName, url, user, password, max);    pools.put(poolName, pool);    log("Initialized pool " + poolName);   }  } }
  一个枚举对象保存所有的属性名,如果属性名带有.url结尾,则表示是一个连接池对象需要被实例化。创建的连接池对象保存在一个Hashtable实例变量中。连接池名字作为索引,连接池对象作为值。
 
  二、得到和返回连接
 
  DBConnectionManager提供getConnection()方法和freeConnection方法,这些方法有客户程序使用。所有的方法以连接池名字所参数,并调用特定的连接池对象。
public Connection getConnection(String name) {  DBConnectionPool pool = (DBConnectionPool) pools.get(name);  if (pool != null) {   return pool.getConnection();  }  return null; } public Connection getConnection(String name, long time) {  DBConnectionPool pool = (DBConnectionPool) pools.get(name);  if (pool != null) {   return pool.getConnection(time);  }  return null; } public void freeConnection(String name, Connection con) {  DBConnectionPool pool = (DBConnectionPool) pools.get(name);  if (pool != null) {   pool.freeConnection(con);  } }
  三、关闭
 
  最后,由一个release()方法,用来完好地关闭连接池。每个DBConnectionManager客户必须调用getInstance()方法引用。有一个计数器跟踪客户的数量。方法release()在客户关闭时调用,技术器减1。当最后一个客户释放,DBConnectionManager关闭所有的连接池。
public synchronized void release() {  // Wait until called by the last client  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("Deregistered JDBC driver " + driver.getClass().getName());   }   catch (SQLException e) {    log(e, "Can not deregister JDBC driver: " + driver.getClass().getName());   }  } }
  当所有连接池关闭,所有jdbc驱动程序也被注销。
 
连结池的作用
 
  现在我们结合DBConnetionManager和DBConnectionPool类来讲解Servlet中连接池的使用:
 
  一、首先简单介绍一下Servlet的生命周期:
 
  Servlet API定义的servlet生命周期如下:
 
  1、 Servlet 被创建然后初始化(init()方法)。
 
  2、 为0个或多个客户调用提供服务(service()方法)。
 
  3、 Servlet被销毁,内存被回收(destroy()方法)。
 
  二、servlet中使用连接池的实例
 
  使用连接池的servlet有三个阶段的典型表现是:
 
  1. 在init()中,调用DBConnectionManager.getInstance()然后将返回的引用保存在实例变量中。
 
  2. 在sevice()中,调用getConnection(),执行一系列数据库操作,然后调用freeConnection()归还连接。
 
  3. 在destroy()中,调用release()来释放所有的资源,并关闭所有的连接。
 
  下面的例子演示如何使用连接池。
import Java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; public class TestServlet extends HttpServlet {  private DBConnectionManager connMgr;  public void init(ServletConfig conf) throws ServletException {   super.init(conf);   connMgr = DBConnectionManager.getInstance();  }  public void service (HttpServletRequest req, HttpServletResponse res)  throws IOException {   res.setContentType("text/html");   PrintWriter out = res.getWriter();   Connection con = connMgr.getConnection("idb");   if (con == null) {    out.println("Cant get connection");    return;   }   ResultSet rs = null;   ResultSetMetaData md = null;   Statement stmt = null;   try {    stmt = con.createStatement();    rs = stmt.executeQuery("SELECT * FROM EMPLOYEE");    md = rs.getMetaData();    out.println("Employee data ");    while (rs.next()) {     out.println(" ");     for (int i = 1; i < md.getColumnCount(); i++) {      out.print(rs.getString(i) + ", ");     }    }    stmt.close();    rs.close();   }   catch (SQLException e) {    e.printStackTrace(out);   }   connMgr.freeConnection("idb", con);  }  public void destroy() {   connMgr.release();   super.destroy();  } }

 

0
相关文章