最新在阅读公司自己写的数据连接池(比较简单的),参考其仿照写了一个数据库连接池,由于过于简单,取名SimpleDataSourceFactory,在tomcat上使用的时候需如下配置:
<GlobalNamingResources>
<Resource name="jdbc/ctpDataSource" auth="Container" factory="com.seeyon.ctp.dbpool.SimpleDataSourceFactory" type="javax.sql.DataSource" />
</GlobalNamingResources>
完整代码如下:
/**
* Author ouyp
* Rev
* Date: 2018年8月2日 下午3:00:42
*
* Copyright (C) 20182017 Seeyon, Inc. All rights reserved.
*
* This software is the proprietary information of Seeyon, Inc.
* Use is subject to license terms.
*/
package com.seeyon.ctp.dbpool;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import javax.sql.DataSource;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import com.seeyon.v3x.dbpool.util.PwdEncoder;
/**
* <p>Title: 简单版数据连接池工厂</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2018</p>
* <p>Company: seeyon.com</p>
* <p>Since Seeyon V7.0</p>
*/
public class SimpleDataSourceFactory implements ObjectFactory {
private static final Log log = LogFactory.getLog(SimpleDataSourceFactory.class);
/**
* 数据源名称
*/
private String name;
/**
* Jdbc地址
*/
private String url;
/**
* jdbc驱动
*/
private String driverClassName;
/**
* 数据库账号
*/
private String username;
/**
* 数据库密码
*/
private String password;
/**
* 最小连接数
*/
private int minCount = 0;
/**
* 最大连接数
*/
private int maxCount = 2000;
/**
* 尝试连接次数
*/
private int tryCount = 5;
/**
* 尝试连接等待时间
*/
private int tryWait = 100;
private static final String datasourceCtp = "A8.datasource.properies.filepath";
private static final Logger logger = Logger.getLogger(SimpleDataSourceFactory.class.getCanonicalName());
/**
* 弱口令
*/
private Set<String> weakPassword = new HashSet<String>(){
private static final long serialVersionUID = 1L;
{
add("123456");
add("111111");
add("222222");
add("333333");
add("444444");
add("555555");
add("666666");
add("777777");
add("888888");
add("999999");
add("000000");
add("123123");
add("abc123");
}
};
/**
* <description>初始化</description>
*
* @author: ouyp
* @since: Seeyon V7.0
* @date: 2018年8月2日 下午4:35:15
*/
private void initialize(Name name) {
this.name = name.get(0);
Properties p = getProperties(System.getProperty(datasourceCtp));
String property = p.getProperty(name + ".url");
if (property != null && property.length() > 0) {
url = property;
}
property = p.getProperty(name + ".driverClassName");
if (property != null && property.length() > 0) {
driverClassName = property;
}
property = p.getProperty(name + ".username");
if (property != null && property.length() > 0) {
username = property;
}
property = p.getProperty(name + ".password");
if (property != null && property.length() > 0) {
password = PwdEncoder.decode(property);
}
property = p.getProperty(name + ".minCount");
if (property != null && property.length() > 0) {
minCount = Integer.parseInt(property);
}
property = p.getProperty(name + ".maxCount");
if (property != null && property.length() > 0) {
maxCount = Integer.parseInt(property);
}
property = p.getProperty(name + ".tryCount");
if (property != null && property.length() > 0) {
tryCount = Integer.parseInt(property);
}
property = p.getProperty(name + ".tryWait");
if (property != null && property.length() > 0) {
tryWait = Integer.parseInt(property);
}
}
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
/**
* 暂停1分钟
*/
TimeUnit.MINUTES.sleep(1);
/**
* 初始化工厂
*/
initialize(name);
try {
/**
* 注入DriverClass
*/
Class.forName(driverClassName);
/**
* 弱口令检测
*/
if (weakPassword.contains(password)) {
String msg = "\r\n*****************************************************\r\n" +
"*\r\n" +
"* 数据库密码存在弱口令风险,系统无法启动\r\n" +
"* 密码要求:长度6位以上,数字字母混合组成\r\n" +
"*\r\n" +
"* 连接池名称:" + this.name + "\r\n" +
"* 数据库驱动:" + this.driverClassName + "\r\n" +
"* 数据库URL: " + this.url + "\r\n" +
"* 数据库账号:" + this.username + "\r\n" +
"*\r\n" +
"*****************************************************";
log.error(msg);
}
/**
* 检查数据库连接是否可以连接
*/
Connection conn = null;
Exception ee = null;
for (int i = 0; i < 10; i ++) {
try {
conn = getConnection();
if (conn != null) {
break;
}
} catch (Exception e) {
ee = e;
log.warn("第" + (i + 1) + "次尝试连接失败,等待10s后重试(还有" + (9 - i) + "次重试机会)...");
} finally {
if (conn != null) {
conn.close();
}
}
}
if (conn == null) {
log.error("第10次尝试连接失败,无法连接数据库,系统无法启动.");
throw ee;
}
} catch (Exception e) {
log.error("无法初始化数据库连接池,系统无法启动");
Thread.sleep(10 * 1000L);
System.exit(-1);
}
return new SimpleDataSource();
}
/**
* <description>获取数据连接</description>
*
* @return
* @throws SQLException
* @author: ouyp
* @since: Seeyon V7.0
* @date: 2018年8月2日 下午4:52:46
*/
private Connection getConnection() throws SQLException {
Connection conn = DriverManager.getConnection(url, username, password);
conn.setAutoCommit(true);
return conn;
}
/**
* <description>多次请求确保能成功获取</description>
*
* @return
* @author: ouyp
* @since: Seeyon V7.0
* @date: 2018年8月2日 下午8:18:12
*/
private ConnectionResult getAquiredConnection() {
ConnectionResult result = new ConnectionResult();
for (int i = 0; i < tryCount; i ++) {
try {
Connection connection = getConnection();
if (connection != null) {
result.connection = connection;
result.success = true;
result.tryTimes = i;
break;
}
Thread.sleep(tryWait);
} catch (InterruptedException e) {
//Igore
} catch (SQLException e) {
if (i == tryCount - 1) {
result.success = false;
result.exp = e;
}
}
}
return result;
}
/**
* <description>获取配置文件信息</description>
*
* @param file
* @return
* @author: ouyp
* @since: Seeyon V7.0
* @date: 2018年8月2日 下午3:30:53
*/
private Properties getProperties(String file) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream(file));
} catch (IOException e) {
log.error("配置文件" + file + "加载失败:", e);
}
return properties;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMinCount() {
return minCount;
}
public void setMinCount(int minCount) {
this.minCount = minCount;
}
public int getMaxCount() {
return maxCount;
}
public void setMaxCount(int maxCount) {
this.maxCount = maxCount;
}
public int getTryCount() {
return tryCount;
}
public void setTryCount(int tryCount) {
this.tryCount = tryCount;
}
public int getTryWait() {
return tryWait;
}
public void setTryWait(int tryWait) {
this.tryWait = tryWait;
}
/**
* <p>Title: 简单版数据连接池</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2018</p>
* <p>Company: seeyon.com</p>
* <p>Since Seeyon V7.0</p>
*/
class SimpleDataSource implements DataSource {
/**
* 正在使用的数据连接
*/
private ConcurrentHashMap<Long, ProxyConnection> usedList = new ConcurrentHashMap<Long, ProxyConnection>();
/**
* 空闲状态的数据连接
*/
private LinkedBlockingDeque<ProxyConnection> idleList = new LinkedBlockingDeque<ProxyConnection>();
/**
* 正常使用数量
*/
private AtomicInteger usedCount = new AtomicInteger(0);
/**
* 闲置数量
*/
private AtomicInteger idleCount = new AtomicInteger(0);
/**
* 峰值
*/
private volatile int peakCount = 0;
private PrintWriter out;
private int loginTimeout;
public SimpleDataSource() throws Exception {
for (int i = 0; i < minCount; i ++) {
ConnectionResult result = getAquiredConnection();
if (result.success) {
ProxyConnection pc = new ProxyConnection(result.connection, this);
idleList.addLast(pc);
idleCount.incrementAndGet();
}
if ((i+1) % 10 == 0) {
if (i == 9) {
log.info("" + (i + 1));
} else {
log.info("," + (i + 1));
}
}
}
log.info("连接池初始化完毕!");
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return out;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
this.out = out;
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
this.loginTimeout = seconds;
}
@Override
public int getLoginTimeout() throws SQLException {
return loginTimeout;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return logger;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
@Override
public Connection getConnection() throws SQLException {
ProxyConnection conn = null;
try {
do {
conn = idleList.pollFirst(tryCount * tryWait, TimeUnit.MILLISECONDS);
if (conn != null) {
idleCount.decrementAndGet();
} else{
break;
}
} while(conn == null || conn.isClosed());
} catch (InterruptedException e) {
log.warn(e.getLocalizedMessage());
}
if (conn == null) {
if (usedCount.intValue() >= maxCount) {
throw new RuntimeException("数据库连接紧张,超过最大连接数,请稍后重试!");
}
ConnectionResult result = getAquiredConnection();
if (result.success) {
conn = new ProxyConnection(result.connection, this);
if (result.tryTimes > 0) {
log.warn("数据库连接不稳定,请及时检查!");
}
usedList.put(conn.getUuid(), conn);
usedCount.incrementAndGet();
} else {
throw result.exp;
}
}
{
int usedInt = usedCount.intValue();
if (usedInt > peakCount) {
peakCount = usedInt;
}
}
return conn;
}
/**
* <description>释放数据连接</description>
*
* @author: ouyp
* @since: Seeyon V7.0
* @date: 2018年8月2日 下午8:58:21
*/
public void releaseConnection(ProxyConnection conn) {
usedList.remove(conn.getUuid());
usedCount.decrementAndGet();
idleList.addLast(conn);
idleCount.incrementAndGet();
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
throw new UnsupportedOperationException();
}
}
/**
* <p>Title: 数据连接</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2018</p>
* <p>Company: seeyon.com</p>
* <p>Since Seeyon V7.0</p>
*/
class ProxyConnection implements java.sql.Connection {
/**
* 原始数据连接
*/
private Connection source;
/**
* 创建时间
*/
private long createTime;
/**
* 数据源
*/
private SimpleDataSource datasource;
/**
* 唯一标志
*/
private long uuid = UUID.randomUUID().getMostSignificantBits();
public ProxyConnection(Connection source, SimpleDataSource datasource) {
super();
this.source = source;
this.createTime = System.currentTimeMillis();
this.datasource = datasource;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return source.unwrap(iface);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return source.isWrapperFor(iface);
}
@Override
public Statement createStatement() throws SQLException {
return source.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return source.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return source.prepareCall(sql);
}
@Override
public String nativeSQL(String sql) throws SQLException {
return source.nativeSQL(sql);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
source.setAutoCommit(autoCommit);
}
@Override
public boolean getAutoCommit() throws SQLException {
return source.getAutoCommit();
}
@Override
public void commit() throws SQLException {
source.commit();
}
@Override
public void rollback() throws SQLException {
source.rollback();
}
@Override
public void close() throws SQLException {
datasource.releaseConnection(this);
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return source.getMetaData();
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
source.setReadOnly(readOnly);
}
@Override
public boolean isReadOnly() throws SQLException {
return source.isReadOnly();
}
@Override
public void setCatalog(String catalog) throws SQLException {
source.setCatalog(catalog);
}
@Override
public String getCatalog() throws SQLException {
return source.getCatalog();
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
source.setTransactionIsolation(level);
}
@Override
public int getTransactionIsolation() throws SQLException {
return source.getTransactionIsolation();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return source.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
source.clearWarnings();
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return source.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
return source.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return source.prepareCall(sql, resultSetType, resultSetConcurrency);
}
@Override
public Map<String, Class<?>> getTypeMap() throws SQLException {
return source.getTypeMap();
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
source.setTypeMap(map);
}
@Override
public void setHoldability(int holdability) throws SQLException {
source.setHoldability(holdability);
}
@Override
public int getHoldability() throws SQLException {
return source.getHoldability();
}
@Override
public Savepoint setSavepoint() throws SQLException {
return source.setSavepoint();
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
return source.setSavepoint(name);
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
source.rollback(savepoint);
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
source.releaseSavepoint(savepoint);
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
return source.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
return source.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
return source.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return source.prepareStatement(sql, autoGeneratedKeys);
}
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return source.prepareStatement(sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return source.prepareStatement(sql, columnNames);
}
@Override
public Clob createClob() throws SQLException {
return source.createClob();
}
@Override
public Blob createBlob() throws SQLException {
return source.createBlob();
}
@Override
public NClob createNClob() throws SQLException {
return source.createNClob();
}
@Override
public SQLXML createSQLXML() throws SQLException {
return source.createSQLXML();
}
@Override
public boolean isValid(int timeout) throws SQLException {
return source.isValid(timeout);
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
source.setClientInfo(name, value);
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
source.setClientInfo(properties);
}
@Override
public String getClientInfo(String name) throws SQLException {
return source.getClientInfo(name);
}
@Override
public Properties getClientInfo() throws SQLException {
return source.getClientInfo();
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return source.createArrayOf(typeName, elements);
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
return source.createStruct(typeName, attributes);
}
@Override
public void setSchema(String schema) throws SQLException {
source.setSchema(schema);
}
@Override
public String getSchema() throws SQLException {
return source.getSchema();
}
@Override
public void abort(Executor executor) throws SQLException {
source.abort(executor);
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
source.setNetworkTimeout(executor, milliseconds);
}
@Override
public int getNetworkTimeout() throws SQLException {
return source.getNetworkTimeout();
}
public Connection getSource() {
return source;
}
public void setSource(Connection source) {
this.source = source;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public SimpleDataSource getDatasource() {
return datasource;
}
public void setDatasource(SimpleDataSource datasource) {
this.datasource = datasource;
}
public long getUuid() {
return uuid;
}
public void setUuid(long uuid) {
this.uuid = uuid;
}
}
/**
* <p>Title: 数据连接封装对象</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2018</p>
* <p>Company: seeyon.com</p>
* <p>Since Seeyon V7.0</p>
*/
class ConnectionResult {
/**
* 是否获取成功
*/
private boolean success;
/**
* 数据连接
*/
private Connection connection;
/**
* 连接次数
*/
private int tryTimes;
/**
* 异常信息
*/
private SQLException exp;
}
}
内部系统会对数据库密码有加密措施,再此就不提供源码了.