数据库连接池小结

简介

1、建立数据库连接池对象(服务器启动)。
2、按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。
3、对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。
4、存取数据库。
5、关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。
6、释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接。

优点

连接池一般比直接连接更有优越性,因为它提高了性能的同时还保存了宝贵的资源。在整个应用程序的使用过程,当中重复的打开直接连接将导致性能的下降。而池连接只在服务器启动时打开一次,从而消除了这种性能问题。

应用连接池的三种方式

  1. 自定义连接池
  2. 使用第三方连接池
  3. 使用服务器自带的连接池

dbcp连接池

连接配置文件

#最大连接数量:连接池在同一时间能够分配的最大活动连接的数量,,如果设置为非正数则表示不限制,默认值8
maxActive=15
#最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建,默认值0
minIdle=5
#最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制,默认值8
maxIdle=10
#初始化连接数:连接池启动时创建的初始化连接数量,默认值0
initialSize=5
#连接被泄露时是否打印
logAbandoned=true
#是否自动回收超时连接
removeAbandoned=true 
#超时时间(以秒数为单位)
removeAbandonedTimeout=180
# 最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间(以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待,默认值无限
maxWait=3000
#在空闲连接回收器线程运行期间休眠的时间值(以毫秒为单位).
timeBetweenEvictionRunsMillis=10000
#在每次空闲连接回收器线程(如果有)运行时检查的连接数量
numTestsPerEvictionRun=8
#连接在池中保持空闲而不被空闲连接回收器线程
minEvictableIdleTimeMillis=10000
#用来验证从连接池取出的连接
validationQuery=SELECT 1
#指明是否在从池中取出连接前进行检验
testOnBorrow=true
#testOnReturn  false  指明是否在归还到池中前进行检验
testOnReturn=true
#设置为true后如果要生效,validationQuery参数必须设置为非空字符串
testWhileIdle

数据库连接池示例

通过构造函数初始化连接的最大上限,通过一个双向队列来维护连接,调用方需要先调用fetchConnection(long)方法来指定在多少毫秒内超时获取连接,连接使用完成后调用releaseConnection(Connection)方法将连接放回线程池。

private LinkedList<Connection> pool = new LinkedList<Connection>();
/**
 * 初始化连接池的大小
 * @param initialSize
 */
public ConnectionPool(int initialSize) {
	if (initialSize > 0) {
		for (int i = 0; i < initialSize; i++) {
			pool.addLast(ConnectionDriver.createConnection());
		}
	}
}
/**
 * 释放连接,放回到连接池
 * @param connection
 */
public void releaseConnection(Connection connection){
	if(connection != null){
		synchronized (pool) {
			// 连接释放后需要进行通知,这样其他消费者能够感知到连接池中已经归还了一个连接
			pool.addLast(connection);
			pool.notifyAll();
		}
	}
}
/**
 * 在mills内无法获取到连接,将会返回null
 * @param mills
 * @return
 * @throws InterruptedException
 */
public Connection fetchConnection(long mills) throws InterruptedException{
	synchronized (pool) {
		// 无限制等待
		if (mills <= 0) {
			while (pool.isEmpty()) {
				pool.wait();
			}
			return pool.removeFirst();
		}else{
			long future = System.currentTimeMillis() + mills;
			long remaining = mills;
			while (pool.isEmpty() && remaining > 0) {
				// 等待超时
				pool.wait(remaining);
				remaining = future - System.currentTimeMillis();
			}
			Connection result = null;
			if (!pool.isEmpty()) {
				result = pool.removeFirst();
			}
			return result;
		}
	}
}

java.sql.Connection是一个接口,最终的实现是由数据库驱动提供方来实现的,通过动态代理构造了一个Connection,该Connection的代理实现仅仅是在commit()方法调用时休眠100毫秒。

static class ConnectionHandler implements InvocationHandler{
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(method.equals("commit")){
			TimeUnit.MILLISECONDS.sleep(100);
		}
		return null;
	}
}
    /**
     * 创建一个Connection的代理,在commit时休眠100毫秒
     * @return
     */
public static final Connection createConnection(){
    return (Connection) Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),
       new Class[] { Connection.class },new ConnectionHandler());
}

通过一个示例来测试简易数据库连接池的工作情况,模拟客户端ConnectionRunner获取、使用、最后释放连接的过程,
当它使用时连接将会增加获取到连接的数量,反之,将会增加未获取到连接的数量。

 

static ConnectionPool pool = new ConnectionPool(10);
// 保证所有ConnectionRunner能够同时开始
static CountDownLatch start = new CountDownLatch(1);
// main线程将会等待所有ConnectionRunner结束后才能继续执行
static CountDownLatch end;
public static void main(String[] args) {
	// 线程数量,可以修改线程数量进行观察
	int threadCount = 10;
	end = new CountDownLatch(threadCount);
	int count = 20;
	AtomicInteger got = new AtomicInteger();
	AtomicInteger notGot = new AtomicInteger();
	for (int i = 0; i < threadCount; i++) {
		Thread thread = new Thread(new ConnetionRunner(count, got, notGot), "ConnectionRunnerThread");
		thread.start();
	}
	start.countDown();
	try {
		end.await();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	System.out.println("total invoke: " + (threadCount * count));
	System.out.println("got connection: " + got);
	System.out.println("not got connection " + notGot);
}

static class ConnetionRunner implements Runnable {
	int count;
	AtomicInteger got;
	AtomicInteger notGot;
	public ConnetionRunner(int count, AtomicInteger got, AtomicInteger notGot) {
		this.count = count;
		this.got = got;
		this.notGot = notGot;
	}
	@Override
	public void run() {
		try {
			start.await();
		} catch (Exception ex) {
		}
		while (count > 0) {
			try {
				// 从线程池中获取连接,如果1000ms内无法获取到,将会返回null
				// 分别统计连接获取的数量got和未获取到的数量notGot
				Connection connection = pool.fetchConnection(1);
				if (connection != null) {
					try {
						connection.createStatement();
						connection.commit();
					} finally {
						pool.releaseConnection(connection);
						got.incrementAndGet();
					}
				} else {
					notGot.incrementAndGet();
				}
			} catch (Exception ex) {
			} finally {
				count--;
			}
		}
		end.countDown();
	}
}

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值