数据库连接池基础- -| 回首页 | 2005年索引 | - -国际戒游戏日

数据库连接池代码

                                      

常用的数据库连接池代码,转载的

总结了一下数据库连接池的用法。

数据库连接是最常用的提高性能的方法,总结了一下:

1 定义数据库访问接口

public interface IDatabaseConnection
{
 public abstract Connection createConnection();
 public abstract void closeConnection(Connection conn);
}

2 实现该接口

2.1 直接连接,连接速度较慢,用户量较大时资源占用很大

public Connection createConnection()
 {
  try
  {
   SystemParameter SP = new SystemParameter();
   Class.forName(DBDRIVER).newInstance();
   Connection con =
    DriverManager.getConnection(
     DBDRIVER_URL,
     DBUSER,
     DBPASSWORD);
   return con;
  }
  catch (ClassNotFoundException e)
  {
   e.printStackTrace();
   return null;
  }
  catch (SQLException e)
  {

   e.printStackTrace();
   return null;
  }
  catch (InstantiationException e)
  {

   e.printStackTrace();
   return null;
  }
  catch (IllegalAccessException e)
  {

   e.printStackTrace();
   return null;
  }
 }
 public void closeConnection(Connection conn)
 {
  if(conn!=null) try
  {
   conn.close();
  }
  catch (SQLException e)
  {
   
   e.printStackTrace();
  }

 }

2.2 DBConnectionManager、DBConnectionPool方式

这个连接池是网上比较多的连接池代码

public class DBConnectionManager
{
 static private DBConnectionManager instance; /*唯一实例*/
 static private int clients;
 /*该计数代表引用DBConnectionManager唯一实例的客户程序总数,
                                      它将被用于控制连接池的关闭操作 */
 //Added by leo on 2001-5-23
 static private String DEFAULTCONNECTIONPOOL = "homepage";

 private Vector drivers = new Vector();
 private PrintWriter logPrint;
 private Hashtable pools = new Hashtable();
 private SystemParameter sp = new SystemParameter();
 /**
 返回唯一实例。如果是第一次调用此方法,则创建实例
 */
 static synchronized public DBConnectionManager getInstance()
 {
  if (instance == null)
  {
   instance = new DBConnectionManager();
  }
  clients++;
  return instance;
 }

 /**
 建构函数私有以防止其它对象创建本类实例
 */
 public DBConnectionManager()
 {
  init();
 }

 /** Added by leo on 2001-5-23
 使用默认的连接池名,创建并返回新连接
 *
 * @return Connection 可用连接或null
 */
 public Connection getConnection()
 {
  return getConnection(DEFAULTCONNECTIONPOOL);
 }

 /**
 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
 限制,则创建并返回新连接
 *
 * @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;
 }

 /** Added by leo on 2001-5-23
   将连接对象返回给默认的连接池
   *
   * @param con 连接对象
   */
 public void freeConnection(Connection con)
 {
  String name = DEFAULTCONNECTIONPOOL;
  freeConnection(name, con);
 }

 /**
 将连接对象返回给由名字指定的连接池
 *
 * @param name 在属性文件中定义的连接池名字
 * @param con 连接对象
 */
 public void freeConnection(String name, Connection con)
 {
  DBConnectionPool pool = (DBConnectionPool) pools.get(name);
  if (pool != null)
  {
   pool.freeConnection(con);
  }
 }

 /**
 关闭所有连接,撤销驱动程序的注册
 */
 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()
 {
  
  String poolName = sp.DBPOOLNAME;
  String url = sp.DBDRIVER_URL;
  String user = sp.DBUSER;
  String password = sp.DBPASSWORD;
  int max = sp.DBMAXCONN;
  
  DBConnectionPool pool =
   new DBConnectionPool(poolName, url, user, password, max);
  pools.put(poolName, pool);
  log("成功创建连接池" + poolName);

 }

 /**
 读取属性完成初始化
 */
 private void init()
 {

  logPrint=new PrintWriter(System.out);
  loadDrivers();
  createPools();
 }

 /**
 装载和注册所有JDBC驱动程序
 *
 * @param props 属性
 */
 private void loadDrivers()
 {
  
   String driverClassName = sp.DBDRIVER;
   try
   {
    Driver driver =
     (Driver) Class.forName(driverClassName).newInstance();
    DriverManager.registerDriver(driver);
    drivers.addElement(driver);
    log("成功JDBC注册驱动程序" + driverClassName);
   }
   catch (Exception e)
   {
    log("无法注册JDBC驱动程序;" + driverClassName + ",错误:" + e);
   }
  
 }

 /**
 将文本信息写入日志文件
 缺省为packaged
 */
 void log(String msg)
 {
  logPrint.println(new java.util.Date() + ": " + msg);
 }

 /**
 将文本信息与异常写入日志文件
 */
 void log(Throwable e, String msg)
 {
  logPrint.println(new java.util.Date() + ": " + msg);
  e.printStackTrace(logPrint);
 }

}

------------------------------------------------------

class DBConnectionPool
{
private int checkedOut;
private PrintWriter logPrint;
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;


logPrint = new PrintWriter(System.out);
 
}

/**
将不再使用的连接返回给连接池
*@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;
}

/**
从连接池获取可用连接,可以指定客户程序能够等待的最长时间
*@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)
{
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;
}

/**
将文本信息写入日志文件
缺省为packaged
*/
void log(String msg)
{
logPrint.println(new Date() + ": " + msg);
}

/**
将文本信息与异常写入日志文件
*/
void log(Throwable e, String msg)
{
logPrint.println(new Date() + ": " + msg);
e.printStackTrace(logPrint);
}
}
---------------------------------

DBConnectionManager connMgr = DBConnectionManager.getInstance();
  public Connection createConnection()
 {

  Connection dBConn = connMgr.getConnection(new SystemParameter().DBPOOLNAME);
  return dBConn;
 }

 public void closeConnection(Connection conn)
 {
  connMgr.freeConnection(new SystemParameter().DBPOOLNAME, conn);
  connMgr.release();

 }

经过测试,使用这种方法,会造成数据库大量死锁,证明该连接池实现方法存在隐患

也可能是因为它不属于webserver容器自身的,不具有可管理性。

2.3 tomcat连接池

public Connection createConnection()
 {

  try
  {
   Context initCtx = new InitialContext();
   DataSource ds;
   ds = (DataSource) initCtx.lookup("java:comp/env/"+new SystemParameter().JDBC_SOURCE);
   return ds.getConnection();
  }
  catch (NamingException e)
  {

   e.printStackTrace();
   return null;
  }
  catch (SQLException e)
  {

   e.printStackTrace();
   return null;
  }

 }

  public void closeConnection(Connection conn)
 {
  if(conn!=null)try
  {
   conn.close();
   conn=null;
  }
  catch (SQLException e)
  {
   
   e.printStackTrace();
  }
  
 }

2.4 weblogic连接池

public Connection createConnection()
 {
  Context ctx = null;
  Hashtable ht = new Hashtable();
  ht.put(Context.INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY);
  ht.put(Context.PROVIDER_URL, URL);
  // ht.put(Context.SECURITY_PRINCIPAL, "admin");
  // ht.put(Context.SECURITY_CREDENTIALS, "11111111");

  Connection conn = null;

  try
  {
   ctx = new InitialContext(ht);
   DataSource ds = (DataSource) ctx.lookup(POOL_NAME);
   return ds.getConnection();
  }
  catch (NamingException e)
  {

   e.printStackTrace();
  }
  catch (SQLException e)
  {

   e.printStackTrace();
  }
  return null;

 }

 public void closeConnection(Connection conn)
 {
  if (conn != null)
   try
   {
    conn.close();
    conn = null;
   }
   catch (SQLException e)
   {

    e.printStackTrace();
   }

 }

3,4的方法比较好

 

乱七八糟 :: 评论 (3) :: 链接 :: 引用 (0)

[回复]

 

不错

 

小林 | 19/11/2004, 16:48

Questions: [回复]

 

1,能不能说明为什么第二种方法造成大量数据死锁?
2,3,4两种方法在该连接不用之后直接close,而不是留给下一位使用者,这样是不是开销会很大?

 

小吴 | 12/01/2005, 03:50

我的理解 [回复]

 

1 第二种可能是因为池的写法有些问题,具体哪里有问题还需要分析,我只能告诉你测试的结果
2 之所以用池,就是从资源池中获取,使用完毕后放回池中,供其它程序使用,始终是连接的,不用每次连接数据库,因而效率会增加。

【作者: pegasus827】【访问统计:】【2005年03月5日 星期六 11:15】【 加入博采】【打印

Trackback

你可以使用这个链接引用该篇文章 http://publishblog.blogchina.com/blog/tb.b?diaryID=874585

回复

- 评论人:gengen   2006-05-19 14:35:10   

3和4在BEAN中怎么调用的?????

验证码:   
评论内容: