Java模拟编写简易数据库连接池

数据库连接池的好处:

对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,频繁的建立、关闭连接,会极大的降低系统的性能,因为数据库的连接是非常耗时的操作,所以可能对于数据库连接就成了系统性能的瓶颈。

 此处,编写一个简单的数据库连接池,理解数据库连接池的实现思想。

数据库连接池的编写分析设计:

参考:https://www.jb51.net/article/78397.htm

数据库连接池的相关配置信息:

/*
 * 数据库连接池的配置文件
 */
public class ParamConfig {
	
	public static final int MIN_CONN=5; //一个连接池最小的连接数
	public static final int MAX_CONN=50;//一个链接池最大的连接数
	public static final int MIN_IDLE=5;//最小空闲连接数
	public static final long MAX_Wait=1000;  //等待获取连接的最长时间

}

 连接数据库信息相关配置文件:DBConfig.properties

# .properties文件,#代表注释

#对于mysql的字段

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/test?useSSL=true&rewriteBatchedStatements=true
mysql.user_name=root
mysql.user_pwd=123456

#Oracle的字段
oracle.driver=
oracle.url=
oracle.user_name=
oracle.user_pwd=

DBHandler接口存储DBConfig.properties的key值:

public interface DBHandler {

	public static String DATABASE="mysql.";
	public static String DRIVER=DATABASE+"driver";
	public static String USER_NAME=DATABASE+"user_name";
	public static String USER_PWD=DATABASE+"user_pwd";
	public static String URL=DATABASE+"url";
	
	
}

数据库连接池的封装:

/*
 * 数据库连接池
 */
public class DBConnPool implements DataSource{
	
	//数据库连接属性
	private static String DRIVER="";
	private static String USER_NAME="";
	private static String USER_PWD="";
	private static String URL="";
	
	private static Properties p=null;
	static{
		//对连接属性进行赋值
		p=new Properties();
		try {
			p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("DBConfig.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		DRIVER=getValue(DBHandler.DRIVER);
		URL=getValue(DBHandler.URL);
		USER_NAME=getValue(DBHandler.USER_NAME);
		USER_PWD=getValue(DBHandler.USER_PWD);
		
	}
	
	private static final int DEFAULT_INIT_SIZE=5;//连接池默认连接数
	private static ArrayBlockingQueue<Connection> idleConnQueue;//空闲连接队列
	private static Vector<Connection> busyConnVector;  //正在被使用的数据库连接集合
	
	private static Logger logger=null;
	
	private int size;//空闲连接数
	
	private static DBConnPool dbConnPool=null;//使用单例模式
	
	private DBConnPool() {
		initConnPool();
	}
	/*
	 * 提供给外界获取此类对象的方法
	 */
	public static DBConnPool getInstance(){
		if(dbConnPool==null){
			dbConnPool=new DBConnPool();
		}
		return dbConnPool;
	}
	/*
	 * 初始化数据库连接池
	 */
	private void initConnPool() {
		//取到最大连接数
		int maxConn=ParamConfig.MAX_CONN;
		//最小连接数
		int minConn=ParamConfig.MIN_CONN;
		idleConnQueue=new ArrayBlockingQueue<>(maxConn);//队列的大小为最大的连接数
		busyConnVector=new Vector<>();
		logger=Logger.getLogger(this.getClass().getName());
		//在默认大小和配置的最小连接数之间选一个大的
		int initSize=minConn<DEFAULT_INIT_SIZE?DEFAULT_INIT_SIZE:minConn;
		
		//加载驱动
		try {
			Class.forName(DRIVER);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		//初始化连接池
		for(int i=0;i<initSize;i++){
			try {
				idleConnQueue.put(newConn());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			size++;
		}
		
	}
	/**
	 * 创建一个连接
	 * @return
	 */
	private Connection newConn() {
		Connection conn=null;
		try {
			conn = DriverManager.getConnection(URL, USER_NAME, USER_PWD);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
	/**
	 * 获取数据库配置文件对应的值
	 * @param key 键
	 * @return 值
	 */
	private static String getValue(String key) {
		if(key==null||"".equals(key)){
			throw new IllegalArgumentException("传入参数有误!");
		}
		return p.getProperty(key);
	}

	/**
	 * 获取连接
	 */
	@Override
	public  Connection getConnection() throws SQLException {
		try {
			//在指定的时间内获取指定的元素,返回队列的头部
			final Connection conn=idleConnQueue.poll(ParamConfig.MAX_Wait,TimeUnit.MILLISECONDS);
			if(conn==null){
				//获取不到连接,给出相应的提示
				logger.info(entryMsg());
				//如果没有连接可以获取,那么需要进行扩容
				ensureCapacity();
				return null;
			}
			busyConnVector.add(conn);
			return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {

						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							if (!method.getName().equals("close")) {
								return method.invoke(conn, args);
							} else {
								idleConnQueue.offer(conn);
								busyConnVector.remove(conn);
								System.out.println(conn);
								return null;
							}
						}
					});
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * 对连接池进行扩容
	 */
	private void ensureCapacity() {
		int minConn=ParamConfig.MIN_CONN; //最小连接数
		int maxConn=ParamConfig.MAX_CONN; //最大连接数
		int newConn=minConn+size; //新的连接数
		newConn=newConn>maxConn?maxConn:newConn;
		
		int modCount=0;
		for(int i=size;i<newConn-size;i++){
			try {
				idleConnQueue.put(newConn());
				modCount++;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		size+=modCount;
	}
	/*
	 * 对数据库连接池进行清空
	 */
	public void clear(){
		while(size-->0){
			try {
				Connection conn=idleConnQueue.take();
				conn.close();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
	}
	/*
	 * 获取空闲队列的大小
	 */
	protected int getIdleConnQueueSize(){
		return idleConnQueue.size();
	}
	/**
	 * 获取正在使用的连接的数量
	 * @return
	 */
	protected int getBusyConnVectorSize(){
		return busyConnVector.size();
	}
	private String entryMsg() {
		return "数据库忙碌,请进行等待。。。";
	}
	@Override
	public Connection getConnection(String username, String password) throws SQLException {
		return null;
	}

	@Override
	public PrintWriter getLogWriter() throws SQLException {
		return null;
	}

	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {

	}

	@Override
	public void setLoginTimeout(int seconds) throws SQLException {
		
	}

	@Override
	public int getLoginTimeout() throws SQLException {
		return 0;
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		return null;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return null;
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

}

数据库连接池的管理类:

public class DBConnPoolManage {
	
	//提供给外界获取连接
	public static Connection getConn() throws SQLException{
		return DBConnPool.getInstance().getConnection();
	}
	
}

测试类:

public class Test {

	public static void main(String[] args) {
		Connection conn=null;
		Statement stmt=null;
		ResultSet rs=null;
		//获取连接
		try {
			conn=DBConnPoolManage.getConn();
			stmt=conn.createStatement();
			String sql="SELECT * FROM USER";
			
			rs=stmt.executeQuery(sql);
			while(rs.next()){
				System.out.println(rs.getString(2));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			try {
				if(conn!=null){
					conn.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(rs!=null){
					rs.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

分析总结:

核心代码:

public  Connection getConnection() throws SQLException {
		try {
			//在指定的时间内获取指定的元素,返回队列的头部
			final Connection conn=idleConnQueue.poll(ParamConfig.MAX_Wait,TimeUnit.MILLISECONDS);
			if(conn==null){
				//获取不到连接,给出相应的提示
				logger.info(entryMsg());
				//如果没有连接可以获取,那么需要进行扩容
				ensureCapacity();
				return null;
			}
			busyConnVector.add(conn);
			return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {

						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							if (!method.getName().equals("close")) {
								return method.invoke(conn, args);
							} else {
								idleConnQueue.offer(conn);
								busyConnVector.remove(conn);
								System.out.println(conn);
								return null;
							}
						}
					});
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

getConnection返回的并不是“真正”的Connection,而是代理类(此处使用匿名类),当用户调用close()方法时,不是对Connection进行close操作,而是将此Connection放回idleConnQueue队列中,从busyConnVector中移除。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值