一.连接池的结构设计
二.数据库配置
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值取模的方法,负载均衡到不同的队列中