代码实现数据库连接池

数据库连接池

1. 数据库连接池原理

在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。

如外部使用者可通过getConnection方法获取数据库连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。

2. 连接池作用

  1. 资源重用
    由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,增进了系统环境的平稳性(减少内存碎片以级数据库临时进程、线程的数量)
  2. 更快的系统响应速度
    数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池内备用。此时连接池的初始化操作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
  3. 新的资源分配手段
    对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接技术。
  4. 统一的连接管理,避免数据库连接泄露
    在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用的连接,从而避免了常规数据库连接操作中可能出现的资源泄露

纯手写数据库连接池

开始之前可以回顾下jdbc的内容

倚赖仅导入驱动即可

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.38</version>
</dependency>
  1. 读取外部配置信息
//外部配置文件信息
public class DbBean {

	/* 链接属性 */
	private String driverName = "com.mysql.jdbc.Driver";

	private String url = "jdbc:mysql://localhost:3306/test";

	private String userName = "root";

	private String password = "root";

	private String poolName = "thread01";// 连接池名字

	private int minConnections = 1; // 空闲池,最小连接数

	private int maxConnections = 10; // 空闲池,最大连接数

	private int initConnections = 5;// 初始化连接数

	private long connTimeOut = 1000;// 重复获得连接的频率

	private int maxActiveConnections = 100;// 最大允许的连接数,和数据库对应 

	private long connectionTimeOut = 1000 * 60 * 20;// 连接超时时间,默认20分钟

	//getter setter
}

其中较为关键的参数为空闲池数量,当有线程获取连接时,会首先判断创建的连接数是否小于maxActiveConnections ,大于线程将进行等待,小于将会从空闲池中进行取,如果能取到,则会放入活动池中,如果取不到,则新建连接,然后再放入活动池中。
释放连接时会首先判断 空闲连接池是否已满,如果已满则直接释放,如果未满则会将连接从活动池转入空闲池中

  1. 创建接口
//连接数据库池
public interface IConnectionPool {

	// 获取连接(重复利用机制)
	public Connection getConnection();

	// 释放连接(可回收机制)
	public void releaseConnection(Connection connection);
}

  1. 创建数据库连接池

/**
 * ####核心参数######
 * 1.空闲线程 容器 没有被使用的连接存放
 * 2.活动线程 容器正在使用的连接
 * ###核心步骤#####
 * 1. 初始化线程池(初始化空闲线程)
 * 2. 调用getConnection方法 --- 获取连接
 * ## 2.1先去freeConnection获取当前连接,存放在activeConnection
 * 3.调用releaseConnection方法 ----释放连接----资源回收
 * ## 3.1获取activeConnection集合连接,转移到 freeConnection集合中
 */
public class ConnectionPool implements IConnectionPool {
	// 使用线程安全的集合 空闲线程 容器 没有被使用的连接存放
	private List<Connection> freeConnection = new Vector<Connection>();
	// 使用线程安全的集合 活动线程 容器 容器正在使用的连接
	private List<Connection> activeConnection = new Vector<Connection>();
	private DbBean dbBean;
	private static AtomicInteger countConne = new AtomicInteger();


	public ConnectionPool(DbBean dbBean) {
		// 获取配置文件信息
		this.dbBean = dbBean;
		init();
	}

	// 初始化线程池(初始化空闲线程)
	private void init(){
		if (dbBean == null) {
			try {
				throw new Exception("配置文件初始化失败");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// 1.获取初始化连接数
		for (int i = 0; i < dbBean.getInitConnections(); i++) {
			// 2.创建Connection连接
			Connection newConnection = newConnection();
			if (newConnection != null) {
				// 3.存放在freeConnection集合
				freeConnection.add(newConnection);
			}
		}

	}

	// 创建Connection连接
	private  Connection newConnection() {
		try {
			Class.forName(dbBean.getDriverName());
			Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(),
					dbBean.getPassword());
			countConne.incrementAndGet();
			return connection;
		} catch (Exception e) {
			return null;
		}

	}

	// 调用getConnection方法 --- 获取连接
	public  Connection getConnection() {

		try {
			Connection connection = null;
			if (countConne.get() < dbBean.getMaxActiveConnections()) {
				// 小于最大活动连接数
				// 1.判断空闲线程是否有数据
				if (freeConnection.size() > 0) {
					// 空闲线程有存在连接
					// ==freeConnection.get(0);freeConnection.remove(0)
					// 拿到在删除
					connection = freeConnection.remove(0);
				} else {
					// 创建新的连接
					connection = newConnection();
				}
				// 判断连接是否可用
				boolean available = isAvailable(connection);
				if (available) {
					// 存放在活动线程池
					activeConnection.add(connection);
				} else {
					countConne.decrementAndGet();
					connection = getConnection();// 怎么使用重试? 递归算法
				}

			} else {
				// 大于最大活动连接数,进行等待
				wait(dbBean.getConnTimeOut());
				// 重试
				connection = getConnection();
			}
			return connection;
		} catch (Exception e) {
			return null;
		}

	}

	// 判断连接是否可用
	public boolean isAvailable(Connection connection) {
		try {
			if (connection == null || connection.isClosed()) {
				return false;
			}
		} catch (Exception e) {

			// TODO: handle exception
		}
		return true;

	}

	// 释放连接 回收
	public void releaseConnection(Connection connection) {
		try {
			// 1.判断连接是否可用
			if (isAvailable(connection)) {
				// 2.判断空闲线程是否已满
				if (freeConnection.size() < dbBean.getMaxConnections()) {
					// 空闲线程没有满
					freeConnection.add(connection);// 回收连接
				} else {
					// 空闲线程已经满
					connection.close();
				}
				activeConnection.remove(connection);
				countConne.decrementAndGet();
				notifyAll();
			}
		} catch (Exception e) {
			// TODO: handle exception
		}

	}

}

创建管理类:


// 管理线程池
public class ConnectionPoolManager {
	private static DbBean dbBean = new DbBean();
	private static ConnectionPool connectionPool = new ConnectionPool(dbBean);

	// 获取连接(重复利用机制)
	public static Connection getConnection() {
		return connectionPool.getConnection();
	}

	// 释放连接(可回收机制)
	public static void releaseConnection(Connection connection) {
		connectionPool.releaseConnection(connection);
	}
}

测试运行结果


public class Test01 {

	public static void main(String[] args) {
		ThreadConnection threadConnection = new ThreadConnection();
		for (int i = 0; i < 2; i++) {
			Thread thread = new Thread(threadConnection, "线程i:" + i);
			thread.start();
		}
	}

}

class ThreadConnection implements Runnable {

	public void run() {
		for (int i = 0; i < 101; i++) {
			Connection connection = ConnectionPoolManager.getConnection();
			System.out.println(Thread.currentThread().getName() + ",connection-"+i+":" + connection);
			ConnectionPoolManager.releaseConnection(connection);
		}
	}

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个 Python 3.x 实现数据库连接池类单例模式的例子,使用了线程安全的单例模式: ```python import sqlite3 from queue import Queue from threading import Lock class ConnectionPool: __instance = None __lock = Lock() @staticmethod def get_instance(): if ConnectionPool.__instance is None: with ConnectionPool.__lock: if ConnectionPool.__instance is None: ConnectionPool.__instance = ConnectionPool() return ConnectionPool.__instance def __init__(self, max_size=10, db_file=':memory:'): self.max_size = max_size self.db_file = db_file self.pool = Queue(maxsize=max_size) for _ in range(max_size): connection = sqlite3.connect(db_file) self.pool.put(connection) def get_connection(self): return self.pool.get() def release_connection(self, connection): self.pool.put(connection) ``` 在上面的例子中,`ConnectionPool` 是一个单例类,它维护了一个 SQLite 数据库连接池。通过 `get_instance` 方法获取单例对象,通过 `get_connection` 方法从连接中获取一个数据库连接,通过 `release_connection` 方法将连接释放回连接。 在构造函数中,我们创建了一个指定大小的连接,并将连接放入队列中。在 `get_connection` 方法中,我们从队列中获取连接,如果队列为空,则会阻塞,直到有可用连接为止。在 `release_connection` 方法中,我们将连接放回队列中。 使用单例模式,可以保证我们只有一个数据库连接池实例,避免了在多个地方同时创建数据库连接池实例的问题。同时,使用线程安全的单例模式,可以保证在多线程环境下,单例对象的创建过程是线程安全的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值