JDBC中提供了一个接口DataSource,所有的连接池都必须实现这个接口
自定义数据库连接池
创建一个连接池,继承DataSource接口并实现方法,其中只需要关注getConnection()一个方法即可,用于获取连接,然后再创建一个将连接 放回连接池的方法
package com.robot.utils;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger;
/**
* 自定义数据库连接池。
*
* @author 张宝旭
*/
public class MyDbUtilsPool implements DataSource {
/**
* 创建容器,保存连接
*/
private static ConcurrentLinkedQueue<Connection> queue = new ConcurrentLinkedQueue<>();
static {
try {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/gp2002?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8";
// 创建多个连接并存放到容器中
for(int i = 0; i < 5; i++) {
Connection connection = DriverManager.getConnection(url, "bao", "123456");
queue.offer(connection);
}
System.out.println("连接池初始化成功");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
/**
* 获取连接。
* @return 连接
*/
@Override
public Connection getConnection() {
Connection connection = null;
synchronized (queue) {
if (queue.size() > 0) {
connection = queue.poll();
}
}
return connection;
}
/**
* 将连接放回连接池。
*
* @param connection 归还的连接
*/
public void release(Connection connection) {
queue.offer(connection);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@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;
}
}
测试
package com.robot.test;
import com.robot.utils.MyDbUtilsPool;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author 张宝旭
*/
public class MyDbUtilsPoolTest {
@Test
public void myPoolTest() throws SQLException {
MyDbUtilsPool myDbUtilsPool = new MyDbUtilsPool();
// 获取10次连接
for(int i = 0; i < 10; i++) {
Connection connection = myDbUtilsPool.getConnection();
if (connection != null) {
System.out.println("获取连接: " + connection.hashCode());
myDbUtilsPool.release(connection);
} else {
System.out.println("没有获取到连接!");
}
}
}
}
数据库连接池中共有5个连接,如果有10个获取连接而不放回,就会出现后5个获取不到连接的情况,所以每次获取连接使用完之后,需要将连接放回连接池中
Druid连接池
- 阿里巴巴开发
- 支持所有JDBC兼容的数据库
- 简单SQL语句用时10微秒以内
- 需要手动导入druid-1.1.5.jar包
测试Druid连接池
package com.robot.test;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import org.junit.Test;
import java.sql.SQLException;
/**
* 测试Druid连接池。
*
* @author 张宝旭
*/
public class DruidPoolTest {
@Test
public void druidTest() throws SQLException {
// 1 创建连接池对象
DruidDataSource dataSource = new DruidDataSource();
// 2 配置参数
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/gp2002?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8");
dataSource.setUsername("bao");
dataSource.setPassword("123456");
// 其它参数
// 初始化大小
dataSource.setInitialSize(10);
// 最大值
dataSource.setMaxActive(50);
// 最小空闲
dataSource.setMinIdle(5);
// 最大等待时间
dataSource.setMaxWait(5000);
// 3 使用
for(int i = 0; i < 100; i++) {
DruidPooledConnection connection = dataSource.getConnection();
System.out.println("连接: " + connection.toString());
connection.close(); // 将连接返回连接池
}
}
}
以上为测试Druid,接下来也为这个连接池写一个工具类
先创建一个配置文件druid.properties,将连接池的配置参数写到配置文件中
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/gp2002?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8
username=bao
password=123456
initialSize=10
maxActive=50
minIdle=5
maxWait=5000
然后创建工具类
只是获取连接的方式变成了从连接池中获取,工具类中的其它方法还是不变的
package com.robot.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author 张宝旭
*/
public class DbPool {
// 创建连接池
private static DataSource dataSource = null;
// 创建线程局部变量
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
static {
try {
Properties properties = new Properties();
InputStream resourceAsStream = DbPool.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(resourceAsStream);
// 初始化连接池
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
System.out.println("连接池初始化失败");
}
}
/**
* 获取连接。
*
* @return 连接
*/
public static Connection getConnection() {
Connection connection = threadLocal.get();
if (connection == null) {
try {
connection = dataSource.getConnection();
threadLocal.set(connection);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("连接失败");
}
}
return connection;
}
/**
* 释放资源
* @param connection 连接
* @param preparedStatement 执行SQL对象
* @param resultSet 结果集
*/
public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
try {
if (connection != null) {
// 判断有没有开启事务
if (!threadLocal.get().getAutoCommit()) {
connection.close();
threadLocal.remove();
}
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用数据库连接池可以减少创建连接带来的消耗,提高效率