数据源设计思想和数据库连接池设计思想基本相似。大家知道在操作数据库程序时,创建连接所占用时间最多,为了提高程序的效率,便出现了数据库连接池技术。
数据库连接池实现原理:在系统启动时便创建一定数量连接,将它们放在线程安全的集合中(这便称为数据库连接池),当某段程序要连接数据库时,不必再去创建连接而直接去从池中去取,这样也就减少了创建连接时间。在关闭连接时,也不是真正关闭而是将其重新放回池中。从而提高系统效能。
一下说我最近写的一个数据源类,仅供大家参考:
package dataSource;
import java.io.File;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
public class DataSource implements javax.sql.DataSource{
/**驱动*/
private String driver;
/**url*/
private String url;
/**用户名*/
private String user;
/**密码*/
private String password;
/**初始化连接数*/
private int initCount;
/**连接池中最大连接数*/
private int maxCount;
/**当前使用连接数*/
private int currentCount=0;
/**等待连接最长时间*/
private int wait=3000;
/**输出日志流*/
private PrintWriter out;
/**连接池*/
private Vector<ConnectionPool> connections;
public DataSource(){
init();
initConnections();
}
/**
* 初始化
*/
private void init(){
Properties prop=new Properties();
try {
InputStream input=DataSource.class.getClassLoader().getResourceAsStream("dataSource.properties");
prop.load(input);
driver=prop.getProperty("driver");
Class.forName(driver);//加载驱动
url=prop.getProperty("url");
user=prop.getProperty("user");
password=prop.getProperty("password");
String itCount=prop.getProperty("initCount");
initCount=itCount==null?1:Integer.parseInt(itCount);
String mCount=prop.getProperty("maxCount");
maxCount=mCount==null?1:Integer.parseInt(mCount);
connections=new Vector<ConnectionPool>();
out=new PrintWriter(new File("c:/datasouce.log"),"UTF-8");
} catch (Exception e) {
e.printStackTrace();
writerLog(e.getMessage());
throw new RuntimeException("装载配置文件错误");
}
}
/**
* 初始化连接池中数据库连接个数
*
*/
private void initConnections(){
for(int i=0;i<initCount;i++){
try {
Connection conn=createConnection();
if(i==0){
DatabaseMetaData metaData=conn.getMetaData();
int dataCount=metaData.getMaxConnections();
writerLog("数据库最大连接数为:"+dataCount);
if(dataCount>0&&maxCount>dataCount){
maxCount=dataCount;
}
}
ConnectionPool pool=new ConnectionPool(conn);
connections.addElement(pool);
} catch (SQLException e) {
e.printStackTrace();
writerLog(e.getMessage());
throw new RuntimeException("初始化连接池错误");
}
}
}
/**
* 创建连接对象
* @return 创建好的连接对象
* @throws SQLException
*/
private Connection createConnection() throws SQLException{
currentCount++;
writerLog("当前正在使用连接数:"+currentCount);
return DriverManager.getConnection(url,user,password);
}
/**
* 当数据源中原有连接已用完时,就创建一个新的数据库连接对象到连接池中
* 且这个连接需要时才被创建,一旦创建就被使用
* @return
* @throws SQLException
*/
private ConnectionPool createConnPool() throws SQLException{
Connection conn=createConnection();
ConnectionPool pool=new ConnectionPool(conn);
pool.setBusy(true);
writerLog("添加一个新的数据库连接对象到连接池中");
return pool;
}
/**
* 从连接池中得到连接对象
*/
public synchronized Connection getConnection() throws SQLException {
if(connections==null){
writerLog("连接池已不存在");
return null;
}
Connection conn=findFreeConnection();
if(conn==null){
if(currentCount<=maxCount){
ConnectionPool conn1=createConnPool();
return conn1.getConn();
}else{
try {
writerLog("正在等待数据库连接 ....");
Thread.sleep(wait);
return findFreeConnection();
} catch (InterruptedException e) {
writerLog(e.getMessage());
e.printStackTrace();
}
}
}
return conn;
}
/**
* 查找当前连接池中还有没有空闲连接
* @return Connection
*/
private Connection findFreeConnection(){
Connection conn=null;
if(connections.size()>0){
Enumeration enu=connections.elements();
while(enu.hasMoreElements()){
ConnectionPool pool=(ConnectionPool)enu.nextElement();
if(!(pool.isBusy())){
conn=pool.getConn();
pool.setBusy(true);
writerLog("找到一个空闲连接");
return conn;
}
}
}
return conn;
}
/**
* 关闭连接对象(实际上并不是真正的关闭,而是将其状态置为空闲)
* @param conn 要关闭连接对象
*/
public synchronized void closeConnection(Connection conn){
currentCount--;
if(connections.size()==0||connections==null){
writerLog("连接池已不存在");
return;
}
Enumeration enu=connections.elements();
while(enu.hasMoreElements()){
ConnectionPool pool=(ConnectionPool)enu.nextElement();
if(pool.getConn()==conn){
pool.setBusy(false);
writerLog("关闭了当前连接");
break;
}
}
out.close();
}
/**
* 单独创建一个连接,不从连接池中去取
*/
public synchronized Connection getConnection(String username, String password)throws SQLException {
writerLog("创建一个独立于连接池的连接对象");
return DriverManager.getConnection(url,username,password);
}
/**
* 获得日志输出流
*/
public PrintWriter getLogWriter() throws SQLException {
return out;
}
/**
* 设置日志输出流
*/
public void setLogWriter(PrintWriter out) throws SQLException {
this.out=out;
}
/**
* 如果当前没有可用连接,设置等待时间 毫秒数
*/
public void setLoginTimeout(int seconds) throws SQLException {
this.wait=seconds;
}
/**
* 或得系统等待连接时间
*/
public int getLoginTimeout() throws SQLException {
return wait;
}
private void writerLog(String errMessage){
out.append("#=========================================#\n");
out.append(errMessage+"\n");
out.append("#=========================================#\n");
}
/**
* 包装到连接池的连接对象
* @author newapps
*/
class ConnectionPool{
/**当前数据库创建连接*/
Connection conn;
/**当前连接是否处于工作状态*/
boolean busy=false;
/**构造函数*/
ConnectionPool(Connection conn){
this.conn=conn;
}
void setBusy(boolean busy){
this.busy=busy;
}
boolean isBusy(){
return busy;
}
void setConn(Connection conn){
this.conn=conn;
}
Connection getConn(){
return conn;
}
}
}
配置文件(dateSource.properties)
#=================================================================================== #各种常用数据库驱动名称 #============mysql Driver==================== #com.mysql.jdbc.Driver #============oracle Driver=================== #oracle.jdbc.driver.OracleDriver #============pointbase Driver================ #com.pointbase.jdbc.jdbcUniversalDriver #============SQL Server Driver=============== #com.microsoft.jdbc.sqlserver.SQLServerDriver #============DB2 Driver====================== #com.ibm.db2.jdbc.app.DB2Driver #=================================================================================== #数据库连接url格式为:"jdbc:子协议:子协议名称//主机名:端口号/数据库名?属性名=属性值&属性名=属性值" #dbUser和dbPassword也可以通过:属性名=属性值方式传入。 #设置数据库的编码格式:useUnicode=true&characterEncoding=GBK #============mysql url============================================================== #jdbc:mysql://<machine_name><:port>/dbname #端口号:默认是 3306 #============oracle url============================================================= #jdbc:oracle:thin:@<machine_name><:port>:dbname #端口号:默认是 1521 #============pointbase url========================================================== #jdbc:pointbase:server://<machine_name><:port>/dbname #端口号:默认是 9092 #============SQL Server url========================================================= #jdbc:microsoft:sqlserver://<machine_name><:port>;DatabaseName=<dbname> #端口号:默认是 1433 #============DB2 url================================================================ #jdbc:db2://<machine_name><:port>/dbname #端口号:默认是 5000 #=================================================================================== #数据库驱动 driver=com.mysql.jdbc.Driver #数据库URL url=jdbc:mysql://127.0.0.1:3306/ajax #连接数据库用户 user=root #连接数据库密码 password=123 #初始化连接数 initCount=1 #连接池中最大连接数 maxCount=50