基于多线程的数据库连接池

 基于多线程的数据库连接池

 

 并支持两种数据库 mssql 和 mysql:

1、ConnectPoool.java

-------------------------------------->> ConnectPoool.java>>>>>>>>>>>>>---------------------------------------------

package com.sinrow.epm.db;

import java.sql.*;
import java.util.*;
import java.io.*;

/**
* <p>
* Title:数据库连接池
* </p>
* <p>
* Description:本连接池支持对失效连接重连、重建连接池,并监控调用者及调用时间
* 本类需要在类路径根中存在db.properties数据库配置文件,文件内容示例:
* drivers=net.sourceforge.jtds.jdbc.Driver
* defaultpoolname.url=jdbc:jtds:sqlserver://127.0.0.1:1433/wapplat;charset=gb2312
* defaultpoolname.user=sa defaultpoolname.password=lutong
* defaultpoolname.maxconn=20
* </p>
* <p>
* Copyright: Copyright (c) 2005
* </p>
* <p>
* Company:lutong
* </p>
*
* @author <a href="mailto:qiang860818@163.com">DBoy</a>
* @version 1.0
*/

public class ConnectPool extends Thread {
/* 连接池,存放已创建但未使用的连接 */
private Stack pool = new Stack();

/* 被返回的数据库连接,将由线程检测并返回到池中 */
private Stack returnedPool = new Stack();

/* 已被取走、正在使用的连接 */
private Map using = new HashMap();

/* 已经创建连接池计数 */
private int created = 0;
/* 当前数据库类型 */
public static String dbtype;
/* JDBC Driver类 */
String drivers = null;

/* 数据库连接字符串 */
String url = null;

/* 数据库连接用户名 */
String user = null;

/* 数据库连接密码 */
String password = null;

/* 连接池最大数 */
int max = 100;

/* 连接池最小数 (还未实现) */
// int min = 10;
/* 空闲连接等待释放的时间(秒) ,(还未实现) */
// int idleTime = 1800;
/* 是否需要停止线程 */
boolean stopThread = false;

/* 各种同步锁对象,据说byte[]对象创建时间最短,占资料最少 */
private byte[] createdLock = new byte[0];
private byte[] usingLock = new byte[0];
private byte[] poolLock = new byte[0];
private byte[] returnedPoolLock = new byte[0];

/* 单实例 */
private static ConnectPool instance = new ConnectPool();

/**
* 私有的构造方法,防止从外部直接实例化
*
*/
private ConnectPool() {
   /* 初始化数据库连接参数 */
init();
//
//   /* 启动服务线程 */
   start();
}

/**
* 从外部取得本类实例的唯一方法
*
* @return ConnectPool
*/
public static ConnectPool getInstance() {
   return instance;
}

/**
* 从连接池中取得一个数据库连接 如果池中已没有连接,则新创建一个连接 被使用的连接放到using对象里
*
* @param caller
* @return
*/
public Connection getConnection(String poolname, String caller) {
   if (null == caller || caller.length() == 0) {
    StackTraceElement[] callerStackTrace = new Throwable()
      .getStackTrace();
 
    caller = callerStackTrace[1].toString();
   }
   Connection conn = null;
   try {
    synchronized (poolLock) {
     conn = (Connection) pool.pop();
    }
   } catch (EmptyStackException e) {
    conn = newConnection();
   }

   if (null != conn) {
    synchronized (usingLock) {
     using.put(conn, new UsingConnection(conn, caller));
    }
   }
   return conn;
}

/**
* 创建一个新的数据库连接
*
* @return
*/
private Connection newConnection() {
   Connection conn = null;
   try {
    if (created < max) {
     Class.forName(drivers);
     /* 张志强修改 不同数据库获取不同链接 */
     if ("mysql".equals(this.dbtype)) {
      conn = DriverManager.getConnection(url);
     } else {
      conn = DriverManager.getConnection(url, user, password);
     }
     /* 不同数据库获取不同链接 */
     if (null != conn) {
      synchronized (createdLock) {
       created++;
      }
     }
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
   return conn;
}

/**
* 返回一个数据库连接到池中,再由线程返回连接池
*
* @param conn
*/
public void freeConnection(Connection conn) {
   freeConnection(null, conn);
}

public void freeConnection(String poolName, Connection conn) {
   if (null != conn) {
    synchronized (returnedPoolLock) {
     returnedPool.push(conn);
    }
   }
}

/**
* 初始化数据库连接使用的参数
*
*/
private void init() {
   InputStream is = getClass().getResourceAsStream("/db.properties");
   Properties dbProps = new Properties();
   try {
    dbProps.load(is);
   } catch (Exception e) {
    System.err.println("不能读取properties文件. " + "请查看确保文件路径正确!");
    return;
   }
   this.dbtype = dbProps.getProperty("defaultdbtype");
   if ("mysql".equals(this.dbtype)) {
    drivers = dbProps.getProperty("mysql.drivers");
    url = dbProps.getProperty("mysql.defaultpoolname.url");
   } else if ("mssql".equals(this.dbtype)) {
    drivers = dbProps.getProperty("mssql.drivers").trim();
    url = dbProps.getProperty("mssql.defaultpoolname.url").trim();
    user = dbProps.getProperty("mssql.defaultpoolname.user").trim();
    password = dbProps.getProperty("mssql.defaultpoolname.password").trim();
   }
   max = Integer.parseInt(dbProps.getProperty("defaultpoolname.maxconn").trim());
}

/**
* 连接服务线程,主要作用: 记录已取走的连接 测试返回的连接是否可用
*/
public void run() {
   Connection conn = null;
   UsingConnection uc = null;
   while (true && !stopThread) {
    /*
    * 处理被返回的数据库连接 判断连接是否由本池创建并发出的,如果不是则直接关闭
    * 如果是则测试连接是否有效,无效从池中删除,有效则返回池中
    */
    while (!returnedPool.empty()) {
     synchronized (returnedPoolLock) {
      conn = (Connection) returnedPool.pop();
     }
     synchronized (usingLock) {
      uc = (UsingConnection) using.get(conn);
     }
     if (null == uc) {
      try {
       conn.close();
      } catch (Exception e) {
      }
     }
     synchronized (usingLock) {
      using.remove(conn);
     }

     if (testOK(conn)) {
      synchronized (poolLock) {
       pool.add(conn);
      }
     } else {
      try {
       conn.close();
      } catch (Exception e) {
      }
      synchronized (createdLock) {
       created--;
      }
     }
    }

    conn = null;
    uc = null;
    /* 避免循环太快 */
    try {
     Thread.sleep(50);
    } catch (InterruptedException ie) {
    }
   }
   stopThread = false;
}

/**
* 测试连接是否正常
*
* @param conn
* @return
*/
public boolean testOK(Connection conn) {
   boolean result = false;
   PreparedStatement pstmt = null;
   ResultSet rs = null;
   try {
    pstmt = conn.prepareStatement("select 1");
    rs = pstmt.executeQuery();
    result = true;
   } catch (Exception e) {
   } finally {
    if (null != rs) {
     try {
      rs.close();
     } catch (Exception e) {
     }
    }
    if (null != pstmt) {
     try {
      pstmt.close();
     } catch (Exception e) {
     }
    }
   }
   return result;
}

/**
* 取得当前正使用的连接信息(HTML格式)
*
* @return
*/
public String getUsingHTMLInfo() {

   StringBuffer info = new StringBuffer();
   info.append("Driver:" + drivers + "<br>");
   info.append("Connect url:" + url + "<br>");
   synchronized (createdLock) {
    info.append("Created connection count:" + created + "<br>");
   }
   synchronized (usingLock) {
    info.append("Using connection count:" + using.values().size()
      + "<br>");
    info
      .append("<table border=1><tr><td>Caller</td><td>Using Time(ms)</td></tr>");
    Iterator it = using.values().iterator();

    UsingConnection uc = null;
    while (it.hasNext()) {
     uc = (UsingConnection) it.next();
     info.append("<tr><td>");
     info.append(uc.getCaller());
     info.append("</td><td>");
     info.append(uc.getUsingTime());
     info.append("</td></tr>");
    }
   }
   info.append("</table>");
   return info.toString();
}

/**
* 释放所有连接,创建新池
*/
public void release() {
   /* 要求停止线程 */
   stopThread = true;

   /* 停等待线程结束,线程结束时会把stopThread置为false */
   int timeout = 0;
   while (stopThread) {
    if (++timeout > 600) {
     break;
    }
    try {
     Thread.sleep(500);
    } catch (InterruptedException ie) {
    }
   }

   /* 创建新连接池实例 */
   instance = new ConnectPool();

   /* 释放所有连接,除了Using,Using是正在使用的且会在新的池里被释放 */
   synchronized (poolLock) {
    while (!pool.isEmpty()) {
     try {
      Connection conn = (Connection) pool.pop();
      conn.close();
     } catch (Exception e) {
     }
    }
   }

   synchronized (returnedPoolLock) {
    while (!returnedPool.isEmpty()) {
     try {
      Connection conn = (Connection) returnedPool.pop();
      conn.close();
     } catch (Exception e) {
     }
    }
   }
}
}

/**
* 用户存储当前被使用的数据库连接信息
*/
class UsingConnection {
private Connection conn = null;

private String caller = null;

long time = 0;

public UsingConnection(Connection conn, String caller) {
   this.conn = conn;
   this.caller = caller;
   time = System.currentTimeMillis();
}

public String getCaller() {
   return caller;
}

public long getUsingTime() {
   return System.currentTimeMillis() - time;
}
}
------------------------------------------------------------------------------------------------------------

2、DateSource.java

--------------------------------------------DateSource.java   >>>>>>>>>---------------------------

/**
* 通过修改dbconfig.properties 获取 MYSQL 或 MSSQL 数据库的连接
* 此文件创建于20090325
*/
package com.sinrow.epm.db;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;

public class DataSource {
public static String type=ConnectPool.dbtype;

private DataSource() {
 
}

public static Connection getConnection() throws ClassNotFoundException,
    SQLException {
   ConnectPool cp=ConnectPool.getInstance();
   Connection conn =cp.getConnection(cp.getName(),
     cp.getName()+"caller");
 
   return conn;
}

public static boolean CloseDB(Connection conn,Statement pamStatement, ResultSet rs) {
   boolean flag = true;
   try {
   
    if (rs != null)
     rs.close();
    if (pamStatement != null)
     pamStatement.close();

   } catch (Exception e) {
    flag = false;
    e.printStackTrace();
   }
   finally{
    ConnectPool.getInstance().freeConnection(conn);
   
   }
   return flag;
}

}

3、配置文件db.properties 放置于 SRC包下。

--------------------------------db.properties》》》》》》》-----

mssql.drivers=net.sourceforge.jtds.jdbc.Driver
mysql.drivers=com.mysql.jdbc.Driver
mssql.defaultpoolname.url=jdbc:jtds:sqlserver://127.0.0.1:1433/mytest;charset=gb2312
mysql.defaultpoolname.url=jdbc:mysql://127.0.0.1:3306/test?user=root&password=root&useUnicode=true&characterEncoding=gbk
mssql.defaultpoolname.user=sa
mssql.defaultpoolname.password=sa
defaultpoolname.maxconn=40
defaultdbtype=mysql

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值