`
aijuans
  • 浏览: 1549374 次
社区版块
存档分类
最新评论

java 简易版本数据库连接池

阅读更多

写了个 Java数据库连接池,具备基本的功能点:
  1、对池中活动连接的重用。
  2、池满时的适时等待。
  3、对空闲连接的适时关闭。

  抛砖引玉,走过路过,不吝赐教。

 

DBConnection.java如下:

 

package db;

import java.sql.Connection;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 封装的连接
 * @author Linkwork, 276247076@qq.com
 * @since 2014年11月01日
 */
public class DBConnection {
    
    /**
     * 原生的连接
     */
    private Connection connection = null;
    
    /**
     * 是否空闲
     */
    private AtomicBoolean idle = null;
    
    /**
     * 最近一次的空闲开始时间
     */
    private volatile long idleStart = 0L;
    
    /**
     * 标识
     */
    private int index = -1;
    
    /**
     * 构造函数
     * @param index 标识
     * @param connection 连接
     * @param idle 是否空闲
     */
    public DBConnection(int index, Connection connection, boolean idle) {
        this.index = index;
        this.connection = connection;
        this.idle = new AtomicBoolean(idle);
    }
    
    /**
     * 释放
     */
    public void release() {
        if (this.idle.compareAndSet(false, true)) {
            this.idleStart = System.currentTimeMillis();
        }
    }

    public Connection getConnection() {
        return connection;
    }

    public AtomicBoolean getIdle() {
        return idle;
    }
    
    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public int getIndex() {
        return index;
    }

    public long getIdleStart() {
        return idleStart;
    }

    public void setIdleStart(long idleStart) {
        this.idleStart = idleStart;
    }
    
}

 DBConnectionPool.java如下:

 

 

package db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

/**
 * 数据库连接池
 * @author Linkwork, 276247076@qq.com
 * @since 2014年11月01日
 */
public class DBConnectionPool extends Thread {
    
    /**
     * 容量
     */
    private volatile int capacity = 1;
    
    /**
     * 驱动
     */
    private String driver = null;
    
    /**
     * 地址
     */
    private String url = null;
    
    /**
     * 用户名
     */
    private String user = null;
    
    /**
     * 密码
     */
    private String password = null;
    
    /**
     * 等待的轮询间隔
     */
    private volatile long waitInterval = 50L;
    
    /**
     * 等待的超时时间,默认 2分钟
     */
    private volatile long waitTimeout = 120000L;
    
    /**
     * 空闲的超时时间,默认 5分钟
     */
    private volatile long idleTimeout = 300000L;
    
    /**
     * 连接集
     */
    private Vector<DBConnection> dbconnectionLst = null;
    
    /**
     * 是否正在进行关闭
     */
    private volatile boolean closing = false;
    
    /**
     * 构造函数
     * @param capacity 容量
     * @param driver 驱动
     * @param url 地址
     * @param user 用户名
     * @param password 密码
     */
    public DBConnectionPool(
            int capacity,
            String driver,
            String url,
            String user,
            String password) {
        this.capacity = capacity;
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.password = password;
        this.dbconnectionLst = new Vector<DBConnection>();
    }
    
    /**
     * 获取 DB连接
     * @return
     */
    public DBConnection getDBConnectionQuietly() {
        try {
            return this.getDBConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 获取 DB连接
     * @return
     * @throws Exception
     */
    public DBConnection getDBConnection() throws Exception {
        long start = System.currentTimeMillis();
        // 当不是正在进行关闭
        while (! this.closing) {
            // 遍历连接集,获取空闲、可用的连接
            for (DBConnection dbconnection: this.dbconnectionLst) {
                if (dbconnection.getIdle().compareAndSet(true, false)) {
                    // 若连接未关闭
                    if (! this.isNullOrClose(dbconnection)) {
                        return dbconnection;
                    } else {
                        if (! this.closing) {
                            dbconnection.getIdle().set(true);
                        }
                    }
                }
            }
            // 若连接的总数未超出容量,则新建连接
            if ((this.dbconnectionLst.size() < this.capacity)
                    && (! this.closing)) {
                synchronized (this.dbconnectionLst) {
                    DBConnection dbconnection = this.createDBConnection(this.dbconnectionLst.size() + 1);
                    this.dbconnectionLst.add(dbconnection);
                    return dbconnection;
                }
            } 
            // 遍历连接集,重用空闲、不可用的连接
            for (DBConnection dbconnection: this.dbconnectionLst) {
                if (dbconnection.getIdle().compareAndSet(true, false)) {
                    // 若连接已关闭
                    if ((null == dbconnection.getConnection())
                            || dbconnection.getConnection().isClosed()) {
                        Connection connection = this.createConnection();
                        dbconnection.setConnection(connection);
                        return dbconnection;
                    } else if (! this.closing) {
                        dbconnection.getIdle().set(true);
                    }
                }
            }
            // 延迟轮询
            Thread.sleep(this.waitInterval);
            long end = System.currentTimeMillis();
            // 若等待超时
            if (end - start > this.waitTimeout) {
                throw new Exception("ERROR_WAIT_TIMEOUT");
            }
            start = end;
        } // while (! this.closing) {
        return null;
    }
    
    /**
     * 关闭连接池中的所有连接
     * @throws Exception
     */
    public void close() {
        this.closing = true;
        // 是否已经关闭
        boolean closed = false;
        // 当未关闭完成
        while (! closed) {
            closed = true;
            try {
                Thread.sleep(this.waitInterval);
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            // 遍历连接集,关闭所有空闲连接
            for (DBConnection dbconnection: this.dbconnectionLst) {
                // 若连接空闲,则关闭该连接,并标记未关闭完成
                if (dbconnection.getIdle().compareAndSet(true, false)) {
                    closed = false;
                    try {
                        if (! this.isNullOrClose(dbconnection)) {
                            dbconnection.getConnection().close();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } // while (true) {
        System.out.println("has closed all!");
    }

    @Override
    public void run() {
        // 当不是正在进行关闭
        while (! this.closing) {
            try {
                // 延迟轮询
                Thread.sleep(this.waitInterval);
                // 遍历连接集,关闭空闲超时的连接
                for (DBConnection dbconnection: this.dbconnectionLst) {
                    // 若连接空闲,且空闲超时
                    if (dbconnection.getIdle().get()
                            && this.idleTimeout(dbconnection)
                            && dbconnection.getIdle().compareAndSet(true, false)) {
                        // 若连接空闲超时
                        if (this.idleTimeout(dbconnection)) {
                            dbconnection.setIdleStart(0L);
                            dbconnection.getConnection().close();
                            System.out.println("【dbconnection-" + dbconnection.getIndex() + "】idle timeout.");
                        }
                        if (! this.closing) {
                            dbconnection.getIdle().set(true);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    public long getWaitTimeout() {
        return waitTimeout;
    }

    public void setWaitTimeout(long waitTimeout) {
        this.waitTimeout = waitTimeout;
    }

    public long getIdleTimeout() {
        return idleTimeout;
    }

    public void setIdleTimeout(long idleTimeout) {
        this.idleTimeout = idleTimeout;
    }

    public long getWaitInterval() {
        return waitInterval;
    }

    public void setWaitInterval(long waitInterval) {
        this.waitInterval = waitInterval;
    }

    /**
     * 创建 DB连接
     * @param index
     * @return
     * @throws Exception
     */
    private DBConnection createDBConnection(int index) throws Exception {
        return new DBConnection(index, this.createConnection(), false);
    }
    
    /**
     * 创建连接
     * @return
     * @throws Exception
     */
    private Connection createConnection() throws Exception {
        Class.forName(this.driver);
        return DriverManager.getConnection(this.url, this.user, this.password);
    }
    
    /**
     * DB连接是否空闲超时
     * @param dbconnection
     * @return
     */
    private boolean idleTimeout(DBConnection dbconnection) {
        return ((dbconnection.getIdleStart() > 0)
                && (System.currentTimeMillis() - dbconnection.getIdleStart() > this.idleTimeout));
    }
    
    /**
     * DB连接是否为空、或已关闭
     * @param dbconnection
     * @return
     * @throws SQLException
     */
    private boolean isNullOrClose(DBConnection dbconnection) throws SQLException {
        return ((null == dbconnection.getConnection())
                || dbconnection.getConnection().isClosed());
    }

}

 DBConnectionPoolTest.java如下

 

 

package db;

import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 测试:数据库连接池
 * @author Linkwork, 276247076@qq.com
 * @since 2014年11月0日
 */
public class DBConnectionPoolTest {
    
    public static void main(String[] args) {
        DBConnectionPool pool = new DBConnectionPool(3, "com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/db", "lw2013qq", "omg2056db4qq");
        pool.setWaitTimeout(10000L);
        pool.setIdleTimeout(40L);
        pool.start();
        testPool(pool);
        pool.close();
    }
    
    /**
     * 测试连接池
     * @param pool
     */
    public static void testPool(DBConnectionPool pool) {
        DBConnection dbconnection = pool.getDBConnectionQuietly();
        if (null != dbconnection) {
            try {
                // 创建表
                dbconnection.getConnection().prepareStatement("create table if not exists test_pool (tp_value int);").execute();
                dbconnection.release();
                mockConcurrent(pool);
                Thread.sleep(1000);
                mockConcurrent(pool);
                Thread.sleep(60);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                dbconnection.release();
            }
        }
    }
    
    /**
     * 模拟多线程并发访问数据库,并发插入 10行数据
     * @param pool
     */
    public static void mockConcurrent(DBConnectionPool pool) {
        for (int index = 0; index < 10; ++ index) {
            final int value = index;
            Thread thread = new Thread() {
                public void run() {
                    DBConnection dbconnection = pool.getDBConnectionQuietly();
                    if (null != dbconnection) {
                        try {
                            // 插入数据
                            PreparedStatement statement = dbconnection.getConnection().prepareStatement("insert into test_pool(tp_value) values(?);");
                            statement.setInt(1, value);
                            statement.execute();
                            StringBuffer msg = new StringBuffer();
                            msg.append("dbconnection index=").append(dbconnection.getIndex())
                                .append(", insert=").append(value)
                                .append(", time=").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
                            System.out.println(msg.toString());
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            dbconnection.release();
                        }
                    }
                }
            };
            thread.start();
        }
    }

}

 运行 DBConnectionPoolTest.java,控制台输出:

 

dbconnection index=1, insert=0, time=2014-11-29 11:20:46 901

dbconnection index=2, insert=2, time=2014-11-29 11:20:46 917

dbconnection index=3, insert=8, time=2014-11-29 11:20:46 917

dbconnection index=2, insert=1, time=2014-11-29 11:20:46 960

dbconnection index=1, insert=4, time=2014-11-29 11:20:46 960

dbconnection index=3, insert=6, time=2014-11-29 11:20:46 984

dbconnection index=2, insert=7, time=2014-11-29 11:20:47 008

dbconnection index=1, insert=9, time=2014-11-29 11:20:47 008

【dbconnection-3】idle timeout.

dbconnection index=1, insert=3, time=2014-11-29 11:20:47 092

dbconnection index=2, insert=5, time=2014-11-29 11:20:47 142

【dbconnection-1】idle timeout.

【dbconnection-2】idle timeout.

dbconnection index=2, insert=1, time=2014-11-29 11:20:47 907

dbconnection index=1, insert=0, time=2014-11-29 11:20:47 929

dbconnection index=3, insert=3, time=2014-11-29 11:20:47 929

dbconnection index=2, insert=4, time=2014-11-29 11:20:47 948

dbconnection index=1, insert=5, time=2014-11-29 11:20:47 982

dbconnection index=3, insert=8, time=2014-11-29 11:20:47 982

 

has closed all!

 

 

欢迎大家访问我的个人网站 萌萌的IT人
5
0
分享到:
评论

相关推荐

    简易的数据库连接池实现

    自定义实现的数据库连接池,并进行加锁,保证线程安全,适合初学者学习。

    数据库连接池及其管理

    用java实现的简易的数据库连接池及其管理 课程设计 编写一关于Microsoft Access数据库连接池及其管理的相关类,要求能从XML配置文件中读取该数据库驱动程序,数据库名,连接池最大连接数,最多等待用户数,查询...

    Java实现数据库连接池简易教程

    主要为大家介绍了Java实现数据库连接池简易教程,感兴趣的小伙伴们可以参考一下

    纯手写简易版的数据库连接池jar包

    纯手写简易版的数据库连接池jar包

    连接池的简易实现demo

    数据库连接池的简易Java实现

    java proxool轻量级数据池

    java proxool 轻量级数据库连接池配置文件,可进行简易的数据库连接操作

    信息办公简易java开源订销管理系统-javainfo

    1、JDK1.4.2以上版本(注意配置java_home路径) ...1、本订销系统程序默认使用数据为连接池使用的apache commons-dbcp-1.2.1管理数据库连接(tomcat自带),确保该包可用.若要使用其它数据库连接沲,需要修改eas

    简易java开源订销管理系统

    1、本订销系统程序默认使用数据为连接池使用的apache commons-dbcp-1.2.1管理数据库连接(tomcat自带),确保该包可用.若要使用其它数据库连接沲,需要修改easyjf-dbo.xml文件中的相应配置。 2、若不能正常访问数据库,...

    Java-web旅游项目实战案例(四个)IDEA项目源码

    Java-web旅游项目实战案例(四个)IDEA项目源码; 4 技术选型 4.1 Web层 a) Servlet:前端控制器 ...c) Filter:过滤器 d) BeanUtils:数据封装 ...j) Druid:数据库连接池 k) JdbcTemplate:jdbc的工具

    ThinkJD:ThinkJD,又名ThinkJDBC,一个简洁而强大的开源JDBC操作库。您可以使用Java像ThinkPHP框架的M方法一样,一行代码搞定数据库操作。 您可以使用一行Java代码来操作数据库,就像ThinkPHP框架的M方法一样

    支持数据库连接池 简易的事务操作 支持调试模式,输出SQL语句 基于DBUtils,Apache出品,长期质量有保障 先见为快: //数据库配置(只需调用一次) D . setDbConfig( " jdbc:mysql://127.0.0.1:3306/Db

    java开源包4

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    JAVA上百实例源码以及开源项目

    百度云盘分享 ... Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText();...

    JAVA上百实例源码以及开源项目源代码

     Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。  部分源代码摘录:  ftpClient = new FtpClient(); //实例化FtpClient对象  String serverAddr=jtfServer.getText(); //得到服务器地址  ...

    java开源包11

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    java开源包101

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    java开源包6

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    java开源包9

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    java开源包8

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    java开源包5

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

    java开源包10

    BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K(运行时需要slf4j和guava的支持,这二者加...

Global site tag (gtag.js) - Google Analytics