`
totoxian
  • 浏览: 1083422 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

自己实现一个数据库连接池

阅读更多

尽管很多Web服务器厂商已经在服务器内嵌入了数据池的实现,比如Tomcat的DBCP数据库连接池.不过由于其内部的机制开发者并不熟悉.从而出现了Bug不知道该如何去解决.

一直以来我也不喜欢用第三方的开发包,所以就自己参考着一本书实现了一个数据库连接池.并且可扩充性也可以.更重要的是自己写的数据库连接池.即便出现了Bug也比较容易找出来.

下面是数据库连接池的代码,提供了几个接口供程序调用.

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

public class DBConnectionManager {
static private DBConnectionManager instance;
static private int clients;
private PrintWriter log;
private Vector drivers = new Vector();
private Hashtable pools = new Hashtable();

static synchronized public DBConnectionManager getInstance() {
if(instance == null){
instance = new DBConnectionManager();
}
clients++;
return instance;
}

private DBConnectionManager(){
init();
}


private void init(){
System.out.println("init 1");
InputStream is = getClass().getResourceAsStream("db.properties");
System.out.println("init 2");
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");
System.out.println("the logFile is :"+logFile);
try{
log = new PrintWriter(new FileWriter(logFile,true),true);
}catch(IOException e){
System.err.println("无法打开日志文件:"+logFile);
log = new PrintWriter(System.err);
}
System.out.println("init 3");
loadDrviers(dbProps);
createPools(dbProps);
}

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 loadDrviers(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);
}
}
}


public void freeConnection(String name,Connection con){
DBConnectionPool pool = (DBConnectionPool)pools.get(name);
if(pool != null){
pool.freeConnection(con);
}
}

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;
}

private void log(String msg){
log.println(new Date()+":"+msg);
}



public void log(Throwable e,String msg){
log.println(new Date()+":"+msg);
e.printStackTrace();
}


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());
}
}
}


public 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;

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;
}

public synchronized void freeConnection(Connection con){
freeConnections.add(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;
}

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("无法关闭连接池"+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("无法创建下列URL的连接:"+URL);
return null;
}
return con;
}
}

}

以下是一个测试用的Servlet例子:

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {

private DBConnectionManager connMgr;

public void destroy() {
connMgr.release();
super.destroy();
}


public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setContentType("text/html;charset=gb2312");
PrintWriter out = response.getWriter();
Connection con = connMgr.getConnection("mysql");
if(con == null){
out.println("不能获取数据库连接.");
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("<H1>职工数据</H1>");
while(rs.next()){
out.println("<BR>");
for(int i = 1;i < md.getColumnCount();i++){
out.print(rs.getString(i)+",");
}
}
stmt.close();
rs.close();
}catch(SQLException e){
e.printStackTrace();
}

connMgr.freeConnection("mysql",con);
}


public void init(ServletConfig conf) throws ServletException {
super.init(conf);
System.out.println("servelt init start");
connMgr = DBConnectionManager.getInstance();
System.out.println("servelt init over");
}

}

下面是数据库连接池的配置文件:

drivers=com.mysql.jdbc.Driver
logfile=d:\\log\\log.txt
mysql.maxconn=2
mysql.url=jdbc:mysql://localhost/test?user=root&password=sunfeng&useUnicode=true&characterEncoding=gb2312
mysql.user=root
mysql.password=sunfeng

以下是数据库里面的数据(我用的是MySQL数据库):

以下是最终的执行结果:

分享到:
评论

相关推荐

    C#高效数据库连接池源码

    `Demo`可能是一个示例应用程序,展示如何使用自定义的数据库连接池。 5. **连接池实现细节**: - **初始化**:在应用程序启动时,连接池会被初始化,预创建一定数量的数据库连接。 - **连接分配**:当应用程序...

    c# mysql数据库连接池实现

    本文将深入探讨如何在C#中使用MySQL数据库连接池。 首先,我们需要了解什么是数据库连接池。数据库连接池是一种资源管理技术,它预先创建并维护一定数量的数据库连接,当应用需要时,可以从池中获取连接,使用完毕...

    数据库连接池java代码实现

    本文将深入探讨如何使用Java代码来实现一个简单的数据库连接池,并解释其核心概念和工作原理。 连接池的基本思想是维护一组预初始化的数据库连接,当应用程序需要时,可以从池中获取一个连接,使用完毕后,再归还回...

    数据库连接池技术详解

    对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。 在较为完备的数据库连接池实现中,可根据...

    Java jdbc数据库连接池总结

    数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来...

    C# 数据库连接池 C# 数据库连接池

    在C#中,主要使用ADO.NET框架来实现数据库连接池。以下是一些关键类和方法: 1. **System.Data.SqlClient.SqlConnection**:这是SQL Server数据库的连接类,支持连接池。在创建`SqlConnection`对象时,如果没有指定...

    delphi实现数据库连接池

    在Delphi这个强大的Windows应用程序开发环境中,实现数据库连接池能够有效地解决频繁创建和销毁数据库连接带来的性能问题。下面我们将详细探讨如何在Delphi中实现数据库连接池,以及其核心概念和优势。 数据库连接...

    数据库连接池代码实现

    接下来,我们将以Java为例,简要介绍如何使用开源库如C3P0、HikariCP或Apache DBCP来实现数据库连接池。 1. **C3P0** 是一个开源的JDBC连接池,提供了数据库连接的自动获取、释放和管理功能。在使用C3P0时,我们...

    数据库连接池的一个简单实现

    本篇文章将详细解析一个简单的Java实现数据库连接池的过程。 首先,我们要理解数据库连接池的基本原理。数据库连接池预先创建并维护一定数量的数据库连接,当应用程序需要访问数据库时,可以从池中获取一个已存在的...

    常用jdbc数据库连接jar包,数据库连接池jar包

    数据库连接池在初始化时会创建一定数量的数据库连接并保存起来,当应用程序需要连接时,可以从池中获取一个已存在的连接,而不是每次都去新建,用完后也不立即关闭,而是归还给连接池。这样可以显著减少建立和释放...

    03-数据库连接池驱动_数据库连接池;驱动_

    其次,Druid是阿里巴巴开源的数据库连接池实现,它不仅是一个连接池,还集成了监控、SQL解析、WebStatFilter等特性。Druid以其强大的监控能力、优秀的性能和全面的功能深受开发者喜爱。它提供了实时的监控界面,可以...

    JAVA 完整的数据库连接池实现

    本文将详细介绍如何在 Java 中实现一个完整的数据库连接池,并探讨其核心概念、工作原理以及如何根据需求进行配置。 首先,我们需要理解数据库连接池的基本概念。数据库连接池是一种对象池设计模式的应用,它维护了...

    自己写的数据库连接池(java)

    在给定的标题“自己写的数据库连接池(java)”中,我们可以推测这是一个用户自定义的数据库连接池实现,可能是为了学习或实践目的。描述提到的“XML版读取属性文件”和“普通的”,暗示了两种不同的配置方式,一种是...

    自己写的数据库连接池

    在这个项目中,你使用Java实现了一个自定义的数据库连接池,应用了代理模式来优化连接管理和提高性能。下面我们将深入探讨这个主题。 首先,让我们了解什么是数据库连接池。在传统的数据库操作中,每当有新的数据库...

    C# 数据库连接池

    数据库连接池是数据库管理系统中的一个重要概念,主要用于优化数据库的连接操作。在C#编程中,数据库连接池可以高效地管理数据库连接,避免频繁创建和销毁连接导致的性能开销。本文将详细介绍C#中数据库连接池的工作...

    配置数据库连接池

    数据库连接池的基本思想是预先创建并维护一定数量的数据库连接,当应用需要与数据库通信时,可以快速地从连接池中获取一个已建立的连接,而不是每次都新建一个。用完后,连接会归还到池中,供其他请求使用,而不是...

Global site tag (gtag.js) - Google Analytics