有关数据库连接池的模拟实现——丑九怪

有关数据库连接池的模拟实现——丑九怪

有关数据库连接池的概念以及存在意义
  • 概念:数据库连接池,顾名思义,是存放数据库连接的地方,当我们打开了一个数据库连接,就可以将他放在一个特有的“池子”里,当我们要使用的时候,就直接在这个“池子”里寻找链接使用。这个池子同时也实现了对数据库连接的添加,删除,监控等管理
  • 存在的意义:首先数据库连接是重要资源,同时大部分对数据库的操作持续时间都不是那么长,没有必要每次操作都打开新的连接,完毕之后在进行关闭(这个是很费时间的)这将会浪费很多资源,所以我们建立数据库连接池。
  • 这里暂且不实现多线程的问题,当两个或更多线程同时拥有同一个数据库连接,然后执行了不同的SQL语句。这种情况,我们可以让一个事物只占一个数据库连接,这样虽然使用了比较多的数据库连接资源,却也大大减小了对数据库连接管理的繁琐和复杂性
数据库连接池的大概实现
  • 这里我用两个类去实现它,第一个用来创建最基本的连接,并且提供得到连接的方法,如下:
	static final List<Connection> connectionPool = new ArrayList<>(); 
											// 创建列表存储连接
											// 这里的connection是我们自己创建的connection类
	private static String driver;
	private static String url;
	private static String user;
	private static String password;

	private static int minCount;            // 最大以及最小连接个数
	private static int maxCount;
	private static int deltaCount;          // 当发现数据库连接池中没有连接时,要增加的连接个数
	private static long timeOut;  	// 最长的连接空闲时间

// 初始化数据库连接池,当然要一个properties文件
static void initDatabase(String path) throws Exception {
		if (path.equals(null)) {
			PropertiesParser.loadProperties("/database.cfg.properties");
		} else {
			PropertiesParser.loadProperties(path);
		}
		driver = PropertiesParser.value("driver");
		url = PropertiesParser.value("url");
		user = PropertiesParser.value("user");
		password = PropertiesParser.value("password");
		
		String minCountStr = PropertiesParser.value("minCount");
		minCount = minCountStr == null ? 3 : Integer.valueOf(minCountStr);
		
		String maxCountStr = PropertiesParser.value("maxCount");
		maxCount = maxCountStr == null ? 50 : Integer.valueOf(maxCountStr);
		
		String deltaCountStr = PropertiesParser.value("deltaCount");
		deltaCount = deltaCountStr == null ? 3 : Integer.valueOf(deltaCountStr);
		
		String timeoutStr = PropertiesParser.value("timeout");
		timeOut = timeoutStr == null ? 60000 : Long.valueOf(timeoutStr);
		
		try {
			Class.forName(driver);          // 加载数据库驱动类
			createConnection(minCount);   	// 创建数据库连接池
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

创建连接池以及对外提供获取连接的方法

private static boolean createConnection(int count) throws Exception {
		int i = 0;
		while (connectionPool.size() < maxCount && i < count) {
			Connection connection = new Connection();
			connection.setConnection(DriverManager.getConnection(url, user, password));
			connectionPool.add(connection);
			i++;
		}
		return connectionPool.size() < maxCount;
	}

// 对外提供的方法,取得数据库连接
Connection getConnection() throws Exception {
		
		for (int i = 0; i < connectionPool.size(); i++) {
			Connection connection = connectionPool.get(i);
			if (connection.isUsed()) {
				continue;
			} else {
				return connection;
			}
		}
		// 能走到这里说明已经没有可以用的链接了,所以创建新的链接之后,递归调用自己
		if (createConnection(deltaCount)) {
			return getConnection();
		}
		
		return null;  // 返回null说明数据库连接池已经满了
	}

下面是有关连接超时的处理,我用一个私有方法处理,用到了之前我做过的工具:滴答滴答(这个工具在我之前的博文里有)(滴答滴答改良版本也可以实现)

private static void scanPool() {
		
		new Didadida() {
			@Override
			public void doIt() {
				for (int index = 0; index < connectionPool.size(); index++) {
					Connection connection = connectionPool.get(index);
					System.out.println(connection);
					// 一个连接没有被使用,并且也已经超时
					if (!connection.isUsed() 
							&& connection.isTimeOut(System.currentTimeMillis(), timeOut)) {
						if ((connectionPool.size() - 1) >= minCount) {
							connection.getConnection().close();
							connectionPool.remove(connection);
						}
					}
				}
			}
			@Override
			public void beforeDida() {
			}
			@Override
			public void afterStopDida() {
			}
		}.setDelayTime(timeOut).start();
	}
  • 用另一个类处理连接应该处理的操作(类名称:connection)
	private java.sql.Connection connection;
	private boolean isUsed;
	private long time;  // 这个时间用来记录
	
	public Connection() {
		isUsed = false;
	}
	
	Connection getConnection() {
		time = System.currentTimeMillis();
		isUsed = true;
		return this;
	}

这里也提供了强制关闭,判断是否连接超时,执行sql语句的方法,一句对于连接的set方法

// 可以超出的时间和当前时间都由外面提供,算出时间差,判断是否为超时连接(超出时间有默认值)
	void ForceClose(long timeOut, long curTime) {
		if (!isUsed) { // 如果没有被使用,呢么默认为空闲连接,也就无需关闭
			return;
		}
		long delayTime = curTime - time;
		if (timeOut <= delayTime) {
			isUsed = false;
		}
	}
	
	// 判断是否超时
	boolean isTimeOut(long timeOut, long curTime) {
		long delayTime = curTime - time;
		if (timeOut <= delayTime) {
			return true;
		}
		return false;
	}
	
	// 执行sql语句的方法
	PreparedStatement preparedStatement(String SQLString) throws SQLException {
		return connection.prepareStatement(SQLString);
	}
	
	void setConnection(java.sql.Connection connection) {
		this.connection = connection;
	}

这两个类之间的联系:第二个connection类,是第一个数据库连接池中的list成员,我们用自己写的connection将对数据库的连接封装起来,用于判断是否超时等等

总结
  • 数据库连接池是对于重要的资源进行有效管理的方法,这本身并没有什么,重要的是我们要有工具思想,大量重复出现的代码要抽象成工具类,关键代码也要做成工具类,这将大大提高我们的注意力,让我们更关心业务本身的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值