自己写MVC框架:(一)数据库连接池

一.连接池的结构设计

自己写MVC框架:(一)数据库连接池_第1张图片

二.数据库配置

1.数据库配置文件

config_db.properties文件放到src下,如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/framwork?useUnicode=true&characterEncoding=UTF-8
username=root
password=123
poolsize=20
autocommite=true

2.读取数据库配置文件

package com.myframework.db;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

/**
 * 用于读取配置文件
 * @author xiajie
 *
 */
public class DBConfig {
	
	public static int MAX_POOL_SIZE = 20;
	public static String URL="";
	public static String DRIVER="";
	public static String USERNAME = "";
	public static String PASSWORD = "";
	//是否自动提交
	public static boolean AUTOCOMMIT = true;
	
	
	static{
		
		//读取配置文件
		Properties properties = new Properties();
		//获取本src文件夹所在的物理的位置(即编译后bin文件夹的绝对路径,在服务器端也可以)
		///D:/WorkSpace-ALL/taotao-workspace/FrameworkByMe/bin/
		String path = DBConfig.class.getResource("/").getPath();
		
		try {
			properties.load(new FileInputStream(path+"config_db.properties"));
			URL = (String)properties.getProperty("url");
			DRIVER = (String)properties.getProperty("driver");
			USERNAME = (String)properties.getProperty("username");
			PASSWORD = (String)properties.getProperty("password");
			MAX_POOL_SIZE =  Integer.parseInt(properties.getProperty("poolsize"));
			AUTOCOMMIT = Boolean.parseBoolean(properties.getProperty("autocommite")); 
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
}

三.管理数据库连接


package com.myframework.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * 用于管理数据库连接
 * @author xiajie
 *
 */
public class DBManager {
	
	/**
	 * 用于初始化数据库连接池
	 */
	public static void initDBPool(){
		
		try {
			Class.forName(DBConfig.DRIVER);
			/**
			 * 创建数据的连接池中的连接对象
			 */
			for(int i=0;i<DBConfig.MAX_POOL_SIZE;i++){
				try {
					
					Connection connection = getConnection();
					connection.setAutoCommit(false);
					DBPool.getInstance().addConnection(connection);
					
				} catch (SQLException e) {
					
					e.printStackTrace();
				}
			}
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 用于获取一个数据库的Connection连接
	 * @return
	 */
	public static Connection  getConnection(){
		
		Connection connection = null;
		try {
			
			connection = DriverManager.getConnection(DBConfig.URL, DBConfig.USERNAME, DBConfig.PASSWORD);
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return connection;
	}
}

四.连接池

package com.myframework.db;

import java.sql.Connection;

/**
 * 连接池的接口
 * @author xiajie
 *
 */
public interface IDBPool {
    
	/**
	 * 获取数据库连接
	 * Connection 是jdk底层对数据连接的封装接口
	 * @return
	 */
	public Connection getConnection();
	
	/**
	 * 释放数据库链接
	 */
	public void relaseConnection(Connection connection);
	
	/**
	 * 添加对数据的一次连接线程
	 * @param connection
	 */
	public void addConnection(Connection connection);
}

package com.myframework.db;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class DBPool implements IDBPool {
	
	private static volatile boolean isInit = false;  
	private static DBPool dbPool = new DBPool();

	private  volatile int  n=0;
	//私有化构造方法是为了让在 new 对象时不能采用new DBPool()的方式
	private DBPool(){}
	
	/**
	 * 使用线程安全的单例模式
	 * <p>Title: getInstance</p>
	 * <p>Description: </p>
	 * @return
	 */
	public synchronized static DBPool getInstance(){
	    if(isInit == false){
	    	isInit  = true;
	    	dbPool.initPool();
	    }
	    
		return dbPool;
	}
	
	public void initPool(){  
        DBManager.initDBPool();  
    }  
	
	/**
	 * 用来存放对数据库一次连接Connection的java并发包中的对象
	 */
	//private static ConcurrentLinkedQueue<Connection> pools = new ConcurrentLinkedQueue<Connection>();  
	private static BlockingQueue<Connection> pools = new LinkedBlockingQueue<Connection>();
	
	@Override
	public Connection getConnection() {
		/**
		 * 从初始时加入了20个connection的队列中获取取出队头的元素
		 * 这样可以保证元素的个数不变
		 */
		Connection conn = null;
		try {
			conn = pools.take();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//防止在使用过程中变为null
		if(conn == null){
			conn = DBManager.getConnection();
		}
		return conn;
	}

	@Override
	public   void relaseConnection(Connection connection) {
		
		try {
			
			if(connection.isClosed() == false){
				
				 pools.add(connection);  
				
			}else{
				
			
				/**
				 * 如果连接已经关闭了,
				 * 为了保证连接池中的线程数量不变,应该在创建一个线程添加到连接线程队列
				 */
				Connection conection = DBManager.getConnection();
				pools.add(conection);
			}
			
			
		} catch (SQLException e) {
				e.printStackTrace();
		}
		
	}

	@Override
	public void addConnection(Connection connection) {
		
		pools.add(connection);
		
	}
	
	
	
	

}

五.线程池连接测试

package com.myframework.db;

import com.mysql.jdbc.Connection;

public class DBTest {
	public static void main(String[] args) {
		for(int i=1;i<=40;i++){
			Connection  connection = (Connection) DBPool.getInstance().getConnection();
			System.out.println(connection+"  "+i);
			DBPool.getInstance().relaseConnection(connection);
		}
	}
}

com.mysql.jdbc.Connection@1a53929c  1
com.mysql.jdbc.Connection@64be4d44  2
com.mysql.jdbc.Connection@9c2df08  3
com.mysql.jdbc.Connection@58c08b39  4
com.mysql.jdbc.Connection@48f478b4  5
com.mysql.jdbc.Connection@2a2096d7  6
com.mysql.jdbc.Connection@418f12dc  7
com.mysql.jdbc.Connection@181f4b24  8
com.mysql.jdbc.Connection@2e7e34db  9
com.mysql.jdbc.Connection@5fc02db5  10
com.mysql.jdbc.Connection@41f8f72f  11
com.mysql.jdbc.Connection@402c507f  12
com.mysql.jdbc.Connection@1d58e2c3  13
com.mysql.jdbc.Connection@368f7f42  14
com.mysql.jdbc.Connection@6ebe20a  15
com.mysql.jdbc.Connection@68450212  16
com.mysql.jdbc.Connection@a8b2139  17
com.mysql.jdbc.Connection@34322a97  18
com.mysql.jdbc.Connection@498a3a46  19
<span style="color:#ff0000;">com.mysql.jdbc.Connection@11f7ef62  20</span>
com.mysql.jdbc.Connection@1a53929c  21
com.mysql.jdbc.Connection@64be4d44  22
com.mysql.jdbc.Connection@9c2df08  23
com.mysql.jdbc.Connection@58c08b39  24
com.mysql.jdbc.Connection@48f478b4  25
com.mysql.jdbc.Connection@2a2096d7  26
com.mysql.jdbc.Connection@418f12dc  27
com.mysql.jdbc.Connection@181f4b24  28
com.mysql.jdbc.Connection@2e7e34db  29
com.mysql.jdbc.Connection@5fc02db5  30
com.mysql.jdbc.Connection@41f8f72f  31
com.mysql.jdbc.Connection@402c507f  32
com.mysql.jdbc.Connection@1d58e2c3  33
com.mysql.jdbc.Connection@368f7f42  34
com.mysql.jdbc.Connection@6ebe20a  35
com.mysql.jdbc.Connection@68450212  36
com.mysql.jdbc.Connection@a8b2139  37
com.mysql.jdbc.Connection@34322a97  38
com.mysql.jdbc.Connection@498a3a46  39
<span style="color:#ff0000;">com.mysql.jdbc.Connection@11f7ef62  40</span>

说明线程池起了作用:不管再多的请求只有这20个线程被创建使用了


六.对连接池的优化思路

1.可以设计多个BolckingQueue

     因为对这个队列的每次take(),put()操作,都把,连接池锁住了。比如说有100个线程去操作队列,但是同时只能有1个线程在put(),take()操作,这时是加锁的,其余的99个线程都要等待。有了多个BolckingQueue后就可以提高操作效率。

2.判断 每一个队列中还有多少,根据队列里存放的数量来动态的分配从哪个队列中取,加到哪个队列中。

3.通过计算hash值取模的方法,负载均衡到不同的队列中







你可能感兴趣的:(自己写MVC框架:(一)数据库连接池)