JDBC链接数据库–mysql
以mysql为例 写一套 自定义数据库连接池
设计思路
java连接mysql 参数:driver,url,username,password
为什么使用连接池:数据库链接的创建和销毁需要花费相当的时间,节省时间;创建资源占用一定内存,节省内存;数据库可承受最大链接,数据库默认有个最大承受数,频繁的短时间创建大量链接,链接并未超时,会导致too many connections…
连接池功能:初始化指定数量链接,缓存起来,用的时候去取,用完了放回,销毁的时候统一销毁
废话不多说,上代码:
JdbcPoolConfig – 连接池参数管理 单例 线程安全
public class JdbcPoolConfig {
private String driver = "com.mysql.jdbc.Driver";// 数据库驱动
private String url = "jdbc:mysql://localhost:3306/test";// 连接数据库地址
private String username = "root";// 数据库用户名
private String password = "123456";// 数据库密码
private int initSize = 3;// 初始化连接数
private int maxSize = 10;// 最大连接数
private long timeOut = 5000;// 超时时间(毫秒)
private static JdbcPoolConfig config = null;
protected JdbcPoolConfig() {
}
static {
config = new JdbcPoolConfig();
}
/**
* 单例获取数据库连接池参数
*
* @return
*/
public static JdbcPoolConfig getJdbcPool() {
return config;
}
//get set 省略
}
JdbcPool– 连接池 单例 线程安全
package top.hahawa.pool;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Vector;
import com.mysql.jdbc.Connection;
public class JdbcPool {
private JdbcPoolConfig config;//连接池参数
private Vector<Connection> initConns;// 初始化连接池
private Vector<Connection> freeConns;// 空闲连接池
private static int activeNum = 0;//当前活动线程数量
private static Hashtable<Integer, Long> timeOut = new Hashtable<>();//超时机制
private JdbcPool(JdbcPoolConfig config) throws ClassNotFoundException, SQLException {
this.config = config;
init();
timeOut();
}
private static JdbcPool pool;
static {
try {
pool = new JdbcPool(JdbcPoolConfig.getConfig());
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
public static JdbcPool getPool() {
return pool;
}
private void init() throws ClassNotFoundException, SQLException {
initConns = new Vector<>(config.getInitSize());
for (int i = 0; i < config.getInitSize(); i++) {
initConns.add(createConn());
}
freeConns = new Vector<>();
}
private Connection createConn() throws ClassNotFoundException, SQLException {
Class.forName(config.getDriver());
Connection conn = (Connection) DriverManager.getConnection(config.getUrl(), config.getUsername(),
config.getPassword());
return conn;
}
public synchronized Connection getConnection() throws ClassNotFoundException, SQLException {
System.out.println("=======有人获取链接start ==========");
System.out.println("当前空闲连接数:" + freeConns.size());
System.out.println("当前固定连接数:" + initConns.size());
System.out.println("当前活动连接数:" + activeNum);
System.out.println();
Connection conn = null;
if (freeConns.size() > 0) {
conn = freeConns.remove(0);
} else {
if (initConns.size() > 0) {
conn = initConns.remove(0);
} else {
// 目前情况 分析 理论 只有一种 就是,链接都被拿出去使用了 ,没有归还
if (activeNum + initConns.size() + freeConns.size() < config.getMaxSize()) {
conn = createConn();
} else {
throw new RuntimeException("链接忙,稍后重试...");
}
}
}
addActiveNum();
System.out.println("=======有人获取链接end ==========");
System.out.println("当前空闲连接数:" + freeConns.size());
System.out.println("当前固定连接数:" + initConns.size());
System.out.println("当前活动连接数:" + activeNum);
System.out.println();
return conn;
}
public synchronized void colse(Connection conn) {
System.out.println("=======有人释放链接 start==========");
System.out.println("当前空闲连接数:" + freeConns.size());
System.out.println("当前固定连接数:" + initConns.size());
System.out.println("当前活动连接数:" + activeNum);
System.out.println();
if (initConns.size() < config.getInitSize()) {
initConns.add(conn);
} else {
freeConns.add(conn);
timeOut.put(conn.hashCode(), System.currentTimeMillis());
}
removeActiveNum();
System.out.println("=======有人释放链接 end==========");
System.out.println("当前空闲连接数:" + freeConns.size());
System.out.println("当前固定连接数:" + initConns.size());
System.out.println("当前活动连接数:" + activeNum);
System.out.println();
}
private synchronized void addActiveNum() {
activeNum++;
}
private synchronized void removeActiveNum() {
activeNum--;
}
private void timeOut() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
for (int i = 0; i < freeConns.size(); i++) {
int hc = freeConns.get(i).hashCode();
while (System.currentTimeMillis() - timeOut.get(hc) >= config.getTimeOut()) {
try {
if (freeConns.contains(freeConns.get(i))) {
freeConns.remove(i).close();
}
} catch (SQLException e) {
e.printStackTrace();
}
timeOut.remove(hc);
System.out.println("检测到有限制链接超时..释放掉");
}
}
}
}
});
t.start();
}
}
测试案例 使用线程池测试
package top.hahawa.pool;
import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.mysql.jdbc.Connection;
public class PoolTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 200, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(10));
for (int i = 0; i < 20; i++) {
AA a = new AA();
executor.execute(a);
}
}
}
class AA extends Thread {
@Override
public void run() {
try {
JdbcPool pool = JdbcPool.getPool();
Connection conn = pool.getConnection();
System.out.println("conn: " + conn);
Thread.sleep(2000);
pool.colse(conn);
} catch (ClassNotFoundException | SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}
结果
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:3
当前活动连接数:0
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:1
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@124df
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:1
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:2
conn: com.mysql.jdbc.JDBC4Connection@6307aef3
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:2
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:3
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@3e210adf
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:3
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:4
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@52b9009
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:4
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:5
conn: com.mysql.jdbc.JDBC4Connection@3aa7cbac
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:5
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:6
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@22e90f55
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:6
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:7
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@45c2443e
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:7
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:8
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@33da6329
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:8
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:9
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@41690a2e
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@3290af7e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@124df
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
conn: com.mysql.jdbc.JDBC4Connection@3e210adf
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@6307aef3
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@52b9009
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@3aa7cbac
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@22e90f55
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@45c2443e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@33da6329
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@41690a2e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
conn: com.mysql.jdbc.JDBC4Connection@3290af7e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8
=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:3
当前活动连接数:7
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:3
当前活动连接数:7
=======有人释放链接 end==========
当前空闲连接数:1
当前固定连接数:3
当前活动连接数:6
=======有人释放链接 start==========
当前空闲连接数:1
当前固定连接数:3
当前活动连接数:6
=======有人释放链接 end==========
当前空闲连接数:2
当前固定连接数:3
当前活动连接数:5
Exception in thread "Thread-20" java.lang.NullPointerException
at top.hahawa.pool.JdbcPool$1.run(JdbcPool.java:118)
at java.lang.Thread.run(Thread.java:748)
=======有人释放链接 start==========
当前空闲连接数:2
当前固定连接数:3
当前活动连接数:5
=======有人释放链接 end==========
当前空闲连接数:3
当前固定连接数:3
当前活动连接数:4
=======有人释放链接 start==========
当前空闲连接数:3
当前固定连接数:3
当前活动连接数:4
=======有人释放链接 end==========
当前空闲连接数:4
当前固定连接数:3
当前活动连接数:3
=======有人释放链接 start==========
当前空闲连接数:4
当前固定连接数:3
当前活动连接数:3
=======有人释放链接 end==========
当前空闲连接数:5
当前固定连接数:3
当前活动连接数:2
=======有人释放链接 start==========
当前空闲连接数:5
当前固定连接数:3
当前活动连接数:2
=======有人释放链接 end==========
当前空闲连接数:6
当前固定连接数:3
当前活动连接数:1
=======有人释放链接 start==========
当前空闲连接数:6
当前固定连接数:3
当前活动连接数:1
=======有人释放链接 end==========
当前空闲连接数:7
当前固定连接数:3
当前活动连接数:0
完结!注意点就是 单例 的线程安全问题 不然多线程环境下 并不是真正的单例
然后就是 连接池 缓存的线程安全 创建连接,提供连接,回收连接,