动态加载数据库连接池
实现背景:对于SQL语句需要在库中配置的数据源加载问题,无法直接使用外部的数据库连接池加载动态配置的数据库
简单的实现方式是使用JDBC单独获取配置信息建立数据库连接,对于连接频繁的数据库连接使用JDBC则不是最好的选择,所以在此需要了解下动态数据库连接池的实现
首先创建初始化动态连接池类
DynamicDataSourcePool.java
package cn.net.topnet.utils;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Created with CosmosRay
*
* @author CosmosRay
* @date 2019/8/15
* Funciton:初始化连接池
*/
public class DynamicDataSourcePool {
private static final Log log = LogFactory.getLog(DynamicDataSourcePool.class);
/**
* 申明C3p0数据连接池变量
*/
private ComboPooledDataSource pool = null;
/**
* 默认的构造方法
*
* @param userName 数据库用户名
* @param pass 数据库密码
* @param url 连接的url
* @param driverClass 数据驱动
*/
public DynamicDataSourcePool(String userName, String pass, String url, String driverClass) {
try {
//创建对象
this.pool = new ComboPooledDataSource();
//设置驱动
this.pool.setDriverClass(driverClass);
//设置连接的url
this.pool.setJdbcUrl(url);
//设置数据库用户名
this.pool.setUser(userName);
//设置数据库密码
this.pool.setPassword(pass);
//当连接池中的连接耗尽的时候c3p0一次同时获取的连接数
this.pool.setAcquireIncrement(3);
//连接关闭时默认将所有未提交的操作回滚
this.pool.setAutoCommitOnClose(false);
//获取连接失败后该数据源将申明已断开并永久关闭
this.pool.setBreakAfterAcquireFailure(false);
//当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。
this.pool.setCheckoutTimeout(1000);
//每60秒检查所有连接池中的空闲连接
this.pool.setIdleConnectionTestPeriod(60);
//初始化时获取10个连接,取值应在minPoolSize与maxPoolSize之间
this.pool.setInitialPoolSize(10);
//连接池中保留的最大连接数
this.pool.setMaxPoolSize(40);
//连接池最小连接数
this.pool.setMinPoolSize(5);
//最大空闲时间,60秒内未使用则连接被丢弃
this.pool.setMaxIdleTime(60);
//c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能通过多线程实现多个操作同时被执行
this.pool.setNumHelperThreads(3);
log.info("数据库连接池初始化成功");
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
/**
* 得到连接
*
* @return
*/
public Connection getConnection() {
try {
return this.pool.getConnection();
} catch (SQLException e) {
log.info("获取连接异常");
e.printStackTrace();
}
return null;
}
/**
* 关闭
*/
public void destroy() {
if (null != this.pool) {
this.pool.close();
}
}
}
创建连接池的管理类
DynamicDataSourcePoolFactory.java
package cn.net.topnet.utils;
import cn.net.topnet.dao.impl.DataSourceDaoImpl;
import cn.net.topnet.pojo.DataSource;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import org.apache.commons.lang3.StringUtils;
import java.sql.Connection;
import java.util.Hashtable;
/**
* Created with CosmosRay
*
* @author CosmosRay
* @date 2019/8/15
* Funciton:该类是连接池的管理类
*/
public class DynamicDataSourcePoolFactory {
private static final Log log = LogFactory.getLog(DynamicDataSourcePool.class);
private static Hashtable<String, DynamicDataSourcePool> hashtable = null;
private static DynamicDataSourcePoolFactory dataSourcePoolFactory;
public DynamicDataSourcePoolFactory() {
}
public static DynamicDataSourcePoolFactory getInstance() {
if (null == dataSourcePoolFactory) {
hashtable = new Hashtable<String, DynamicDataSourcePool>();
dataSourcePoolFactory = new DynamicDataSourcePoolFactory();
}
return dataSourcePoolFactory;
}
/**
* 绑定连接池
*
* @param key 连接池的名称必须唯一
* @param dataSourcePool 对应的连接池
*/
public void bind(String key, DynamicDataSourcePool dataSourcePool) {
if (IsBePool(key)) {
getDynamicDataSourcePool(key).destroy();
}
hashtable.put(key, dataSourcePool);
}
/**
* 重新绑定连接池
*
* @param key 连接池的名称必须唯一
* @param dataSourcePool 对应的连接池
*/
public void rebind(String key, DynamicDataSourcePool dataSourcePool) {
if (IsBePool(key)) {
getDynamicDataSourcePool(key).destroy();
}
hashtable.put(key, dataSourcePool);
}
/**
* 删除动态数据连接池中名称为key的连接池
*
* @param key
*/
public void unbind(String key) {
if (IsBePool(key)) {
getDynamicDataSourcePool(key).destroy();
}
hashtable.remove(key);
}
/**
* 查找动态数据连接池中是否存在名称为key的连接池
*
* @param key
* @return
*/
public boolean IsBePool(String key) {
return hashtable.containsKey(key);
}
/**
* 根据key返回key对应的连接池
*
* @param key
* @return
*/
public DynamicDataSourcePool getDynamicDataSourcePool(String key) {
if (!IsBePool(key)) {
return null;
}
return (DynamicDataSourcePool) hashtable.get(key);
}
/**
* 获取数据库连接
*
* @param dataSourcePoolName
* @return
*/
public Connection getConnection(String dataSourcePoolName) {
if (StringUtils.isBlank(dataSourcePoolName)) {
return null;
}
Connection conn;
if (!DynamicDataSourcePoolFactory.getInstance().IsBePool(dataSourcePoolName.trim())) {
DataSourceDaoImpl dataSourceDao = new DataSourceDaoImpl();
DataSource dataSource = dataSourceDao.getDataSource(dataSourcePoolName);
buildDataSourcePool(dataSource);
}
conn = DynamicDataSourcePoolFactory.getInstance().getDynamicDataSourcePool(dataSourcePoolName.trim()).getConnection();
return conn;
}
public static String buildDataSourcePool(DataSource dataSource) {
if (dataSource == null) {
return "<p style='color:red'>数据源对象为 null,请检查数据库</p>";
}
//判断 数据库驱动、数据库连接、数据库用户名不为空 密码可为空
if (StringUtils.isBlank(dataSource.getDriver()) || StringUtils.isBlank(dataSource.getUrl()) || StringUtils.isBlank(dataSource.getUserName())) {
log.info("================================================================");
log.info("Error:Database configuration in the support library is incomplete");
return "<p style='color:red'>Error:Database configuration in the support library is incomplete</p>";
}
DynamicDataSourcePoolFactory factory = DynamicDataSourcePoolFactory.getInstance();
if (factory.IsBePool(dataSource.getName().trim())) {
return "<p style='color:#F9CC9D'>Info:The data source already exists:" + dataSource.getName().trim()+"</p>";
}
DynamicDataSourcePool dataSourcePool = new DynamicDataSourcePool(dataSource.getUserName().trim(), dataSource.getUserPassword().trim(), dataSource.getUrl().trim(), dataSource.getDriver().trim());
//数据源连接池绑定
factory.bind(dataSource.getName().trim(), dataSourcePool);
//判断数据库连接池是否注册成功
if (factory.IsBePool(dataSource.getName().trim())) {
log.info("Success:Successfully registered a new database connection pool:" + dataSource.getName().trim());
return "<p style='color:#7CD03B'>Success:Successfully registered a new database connection pool:" + dataSource.getName().trim()+"</p>";
} else {
log.info("Error:Failed to register a new database connection pool:" + dataSource.getName().trim());
return "<p style='color:red'>Error:Failed to register a new database connection pool:" + dataSource.getName().trim()+"</p>";
}
}
}
对于本次实现,我是在外部创建了实例类 DataSource.java
package cn.net.topnet.pojo;
/**
* Created with CosmosRay
*
* @author CosmosRay
* @date 2019/8/16
* Funciton: 数据源信息
*/
public class DataSource {
private String id;
//数据源别名,连接池绑定名称
private String name;
private String type;
//数据库连接驱动
private String driver;
//数据库连接
private String url;
//用户名
private String userName;
//用户密码
private String userPassword;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
通过调用管理类DynamicDataSourcePoolFactory.java 中的 buildDataSourcePool(DataSource dataSource) 方法,将数据源动态配置成连接池
获取数据库连接
Connection conn = DynamicDataSourcePoolFactory.getInstance().getConnection(DataSource.getName());
CosmosRay |
||
cosmosray@aliyun.com |