数据库连接池的实现

一、设计数据库连接池
将数据库连接池可以作为一个容器,在这个容器里边含有Connection(JDBC接口),可以将Connection作为一个管道,每一次线程获取Connection(获取管道)后进行数据库操作。
1、Connection的存储结构选择Linkedlist
2、线程释放管道:从Linkedlist删除该管道,通过wait-notify唤醒阻塞线程
3、线程获取管道:选择两种模式:无超时等待模式、超时等待模式,无超时等待每一个线程获取连接池锁之后,直接等待获取管道,这就造成了资源的独占,增加负担;超时模式,在获得锁之后,首先在一定的时间限制内则循环等待,如果在等待期间,获得到管道则返回,超过限定时间无法获得管道返回null;

/**
 * 1、超时机制 2、wait-notify
 * 
 * @author 12803
 *
 */
public class ConnectionPool {
	LinkedList<Connection> pool = new LinkedList<>();

	public ConnectionPool(int initialValue) {
		for (int i = 0; i < initialValue; i++) {
			// Connection conn =
			// DriverManager.getConnection(DbconfigXML.jdbcUrl,
			// DbconfigXML.jdbcName,
			// DbconfigXML.jdbcPassword);
			Connection conn = ConnectionDriver.createConnection();
			pool.addFirst(conn);
		}
	}

	/**
	 * 数据库连接池释放一个连接
	 * 
	 * @param conn
	 */
	public void releaseConn(Connection conn) {
		synchronized (pool) {
			pool.addFirst(conn);
			pool.notifyAll();
		}
	}

	public Connection getConnectionfromPool(long mills) throws InterruptedException {
		synchronized (pool) {
			// 无超时等待
			if (mills <= 0) {
				while (pool.isEmpty()) {
					pool.wait();
				}
				return pool.removeFirst();
			} else {
				// 延时等待
				long future = System.currentTimeMillis() + mills;
				long remain = mills;
				while (pool.isEmpty() && remain > 0) {
					pool.wait(remain);
					remain = future - System.currentTimeMillis();
				}
				Connection result = null;
				if (!pool.isEmpty()) {
					result = pool.removeFirst();
				}
				return result;

			}
		}
	}

}

二、动态代理模拟数据库驱动
1、继承InvocationHandler,用做代理对象(proxy)调用处理程序,正常情况在内部需要绑定真实对象。
2、通过动态代理产生Connection
3、现阶段对动态代理理解不太深,参考博客:https://blog.csdn.net/yaomingyang/article/details/80981004

public class ConnectionDriver {
	static class Handler implements InvocationHandler {
		@Override
		/**
		 * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
		 * method:我们所要调用某个对象真实的方法的Method对象 
		 * args:指代代理对象方法传递的参数
		 */
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			if (method.getName().equals("commit")) {
				TimeUnit.MILLISECONDS.sleep(100);
			}
			return null;
		}

	}
	public static final Connection createConnection() {
		/**
		 * ConnectionDriver.class.getClassLoader():通过ConnectionDriver类的加载器加载
		 * new Class<?>[] {Connection.class}:加载Connection类
		 * new Handler():关联的调用处理程序
		 */
		Connection connection = (Connection) Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),
				new Class<?>[] {Connection.class}, new Handler());
		return connection;
	}


}

三、多线程测试
1、设置CountDownLatch start:保证所有线程同时开始(设置为1)
2、设置CountDownLatch end:保证所有线程同时结束(设置为线程数)
3、AtomicInteger get = new AtomicInteger();获取到Connection的线程数
AtomicInteger Notget = new AtomicInteger();未获取到Connection的线程数

public class ConnectionPoolTest {
	static ConnectionPool pool = new ConnectionPool(10);

	// 保证所有线程同时开始
	static CountDownLatch start = new CountDownLatch(1);
	// 保证线程同时结束
	static CountDownLatch end;

	public static void main(String[] args) {
		int ThreadCount = 15;
		end = new CountDownLatch(ThreadCount);
		int count = 20;//表明每一个线程的获取次数
		AtomicInteger get = new AtomicInteger();
		AtomicInteger Notget = new AtomicInteger();
		System.out.println("准备子线程");
		for (int i = 0; i < ThreadCount; i++) {
			Thread thread = new Thread(new MyRunner(count, get, Notget), "ConnectionRunnerThread_"+i);
			thread.start();
		}
		start.countDown();// 让所有线程开始运行
		try {
			end.await();// 主线程等待所有子线程完成
			System.out.println("所有子线程结束");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("total invoke:" + (ThreadCount * count));//总共有ThreadCount个线程,每一个线程获取count次
		System.out.println("Get:" + get);
		System.out.println("Not Get:" + Notget);
	}

	static class MyRunner implements Runnable {
		int count;
		AtomicInteger get;
		AtomicInteger Notget;

		public MyRunner(int count, AtomicInteger get, AtomicInteger Notget) {
			this.count = count;
			this.get = get;
			this.Notget = Notget;
		}

		@Override
		public void run() {

			try {
				start.await();// 等待主线程信号,启动子线程
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("子线程:"+Thread.currentThread().getName());
			while (count > 0) {
				try {
					Connection connection = pool.getConnectionfromPool(100);
					if (connection != null) {
						try {
							connection.createStatement();
							connection.commit();
						} finally {
							pool.releaseConn(connection);
							get.incrementAndGet();
						}
					} else {
						Notget.incrementAndGet();
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					count--;
				}
			}
			end.countDown();// 当前子线程运行结束
		}

	}

}

四、运行结果分析:
1、其中在测试代码中ThreadCount*count含义:假定一个数据库,有ThreadCount个用户,每个用户访问count次

准备子线程
子线程:ConnectionRunnerThread_10
子线程:ConnectionRunnerThread_11
子线程:ConnectionRunnerThread_8
子线程:ConnectionRunnerThread_9
子线程:ConnectionRunnerThread_7
子线程:ConnectionRunnerThread_6
子线程:ConnectionRunnerThread_4
子线程:ConnectionRunnerThread_5
子线程:ConnectionRunnerThread_0
子线程:ConnectionRunnerThread_1
子线程:ConnectionRunnerThread_3
子线程:ConnectionRunnerThread_13
子线程:ConnectionRunnerThread_2
子线程:ConnectionRunnerThread_14
子线程:ConnectionRunnerThread_12
所有子线程结束
total invoke:300
Get:214
Not Get:86

五、结论
当客户端线程逐步增加,客户端无法获取连接的比率增加,不会让客户端线程一直挂在获取联机的操作上,而是按时返回,给用户告知错误,是系统的保护机制。

OVER

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值