访问数据库的主类:package gpsstdserver;
import java.sql.*;
import java.util.Date;
import java.io.PrintWriter;
import java.util.Properties;
import java.util.Enumeration;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
public class AccessDB {
static AccessDB accessdb=null;
public static final int MAX_CON_COUNT=200;
public static final int MIN_CON_COUNT=1; /**
* 定义一个连接池,用来存放连接
*/
private ArrayList conPool=null;
public AccessDB() {
if(conPool==null)
conPool=new ArrayList(0);
MyConnection mycon=new MyConnection();
conPool.add(mycon); }
/**
* 得到一个访问数据库的实例.
* 此访问数据库的类为单例模式.
* 如果成功建立了和数据库的连接,则返回它的实例;
* 否则,返回空
* @return
*/
public synchronized static AccessDB getInstance(){
if(accessdb==null)
accessdb = new AccessDB(); return accessdb; }
/**
* 从连接池中得到一个可用的STATEMENT.
* @return 如果正在访问数据库的客户端的数目大于MAX_CON_COUNT*MAX_STMT_COUNT,返回NULL
*/
private synchronized Statement getStmt(){
MyConnection conn=null;
Statement stmt=null; /**
* 如果连接池为空,那么为连接池开辟一个空间,同时创建一个新的连接加入到连接池中.
*/
if(conPool==null){
conPool = new ArrayList(0);
conn=new MyConnection();
conPool.add(conn);
} /**
* 从连接池中取出一个连接的STATEMENT.如果连接池中的每个连接上的STATEMENT都已经达到
* 了规定的最大值,那么重新为客户端创建一个新的数据库连接.
*/
for(int i=0;i<conPool.size();i++){
conn = (MyConnection) conPool.get(i);
stmt = conn.getStmt();
if (stmt != null)
break;
}
if(stmt==null && conPool.size()<MAX_CON_COUNT)
{
conn=new MyConnection();
stmt=conn.getStmt();
conPool.add(conn);
}
return stmt; } /**
* 关闭一个连接上的STATEMENT.如果关闭后,此连接上没有一个STATEMENT的话,并且此时连接池
* 中的连接数大于MIN_CON_COUNT的话,同时关闭此连接.
* @param st
*/
private synchronized void stmtClose(Statement st){
MyConnection conn=null;
if(conPool!=null && conPool.size()>0){
for(int i=0;i<conPool.size();i++){
conn=(MyConnection )conPool.get(i);
conn.closeStmt(st);
if(conn.stmtCount()<=0 && conPool.size()>MIN_CON_COUNT){
conn.closeConn();
conPool.remove(i);
System.out.println("目前的连接数为:\n"+(conPool.size()-1));
break;
} } }
}
/**
* 查询远程数据库,并且返回一个记录集
* @param sql 要查询的SQL语句
* @return 记录集
*/
public MyResultSet queryDB(String sql){ Statement stmt=null; /**
* 查询数据库,并把返回的内容写到标准的容器中,而不是直接返回RESULTSET。
* 每次查询结束后,并关闭和数据的STATEMENT,在访问数据库之后马上就关闲可以
* 预防客户端忘记关闭而导致的游标越界。
*/
if(sql!=null){
try{
stmt = getStmt();
ResultSet rs=null;
if(stmt!=null){
rs = stmt.executeQuery(sql);
MyResultSet myRs = new MyResultSet(rs);
rs.close();
stmtClose(stmt);
return myRs;
}
}catch(SQLException e){ String err="无法进行数据库查询!"+
"\n"+sql+
"\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
return null;
} /**
* 执行诸如:INSERT,UPDATE,DELETE操作
* @param sql SQL语句
* @return 如果成功执行SQL语句则返回TRUE
*/
public int execute(String sql){
int updateCount=0;
if(sql!=null){
try{
Statement stmt = getStmt();
if(stmt!=null){
stmt.execute(sql);
updateCount = stmt.getUpdateCount();
stmtClose(stmt);
return updateCount;
}
}catch(SQLException e){
//printStackTrace();
String err="更新数据库时出错\n"+
"*"+sql+
"\n*"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
return 0;
}
}
import java.sql.*;
import java.util.Date;
import java.io.PrintWriter;
import java.util.Properties;
import java.util.Enumeration;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
public class AccessDB {
static AccessDB accessdb=null;
public static final int MAX_CON_COUNT=200;
public static final int MIN_CON_COUNT=1; /**
* 定义一个连接池,用来存放连接
*/
private ArrayList conPool=null;
public AccessDB() {
if(conPool==null)
conPool=new ArrayList(0);
MyConnection mycon=new MyConnection();
conPool.add(mycon); }
/**
* 得到一个访问数据库的实例.
* 此访问数据库的类为单例模式.
* 如果成功建立了和数据库的连接,则返回它的实例;
* 否则,返回空
* @return
*/
public synchronized static AccessDB getInstance(){
if(accessdb==null)
accessdb = new AccessDB(); return accessdb; }
/**
* 从连接池中得到一个可用的STATEMENT.
* @return 如果正在访问数据库的客户端的数目大于MAX_CON_COUNT*MAX_STMT_COUNT,返回NULL
*/
private synchronized Statement getStmt(){
MyConnection conn=null;
Statement stmt=null; /**
* 如果连接池为空,那么为连接池开辟一个空间,同时创建一个新的连接加入到连接池中.
*/
if(conPool==null){
conPool = new ArrayList(0);
conn=new MyConnection();
conPool.add(conn);
} /**
* 从连接池中取出一个连接的STATEMENT.如果连接池中的每个连接上的STATEMENT都已经达到
* 了规定的最大值,那么重新为客户端创建一个新的数据库连接.
*/
for(int i=0;i<conPool.size();i++){
conn = (MyConnection) conPool.get(i);
stmt = conn.getStmt();
if (stmt != null)
break;
}
if(stmt==null && conPool.size()<MAX_CON_COUNT)
{
conn=new MyConnection();
stmt=conn.getStmt();
conPool.add(conn);
}
return stmt; } /**
* 关闭一个连接上的STATEMENT.如果关闭后,此连接上没有一个STATEMENT的话,并且此时连接池
* 中的连接数大于MIN_CON_COUNT的话,同时关闭此连接.
* @param st
*/
private synchronized void stmtClose(Statement st){
MyConnection conn=null;
if(conPool!=null && conPool.size()>0){
for(int i=0;i<conPool.size();i++){
conn=(MyConnection )conPool.get(i);
conn.closeStmt(st);
if(conn.stmtCount()<=0 && conPool.size()>MIN_CON_COUNT){
conn.closeConn();
conPool.remove(i);
System.out.println("目前的连接数为:\n"+(conPool.size()-1));
break;
} } }
}
/**
* 查询远程数据库,并且返回一个记录集
* @param sql 要查询的SQL语句
* @return 记录集
*/
public MyResultSet queryDB(String sql){ Statement stmt=null; /**
* 查询数据库,并把返回的内容写到标准的容器中,而不是直接返回RESULTSET。
* 每次查询结束后,并关闭和数据的STATEMENT,在访问数据库之后马上就关闲可以
* 预防客户端忘记关闭而导致的游标越界。
*/
if(sql!=null){
try{
stmt = getStmt();
ResultSet rs=null;
if(stmt!=null){
rs = stmt.executeQuery(sql);
MyResultSet myRs = new MyResultSet(rs);
rs.close();
stmtClose(stmt);
return myRs;
}
}catch(SQLException e){ String err="无法进行数据库查询!"+
"\n"+sql+
"\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
return null;
} /**
* 执行诸如:INSERT,UPDATE,DELETE操作
* @param sql SQL语句
* @return 如果成功执行SQL语句则返回TRUE
*/
public int execute(String sql){
int updateCount=0;
if(sql!=null){
try{
Statement stmt = getStmt();
if(stmt!=null){
stmt.execute(sql);
updateCount = stmt.getUpdateCount();
stmtClose(stmt);
return updateCount;
}
}catch(SQLException e){
//printStackTrace();
String err="更新数据库时出错\n"+
"*"+sql+
"\n*"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
return 0;
}
}
/**
* 建立一个和数据库的物理连接,在此连接上可以建立最多250个STATEMENT。
*/
class MyConnection{
String dbHost=null;//数据库主机地址
int dbPort=0;//数据库端口号
String serviceName=null;//全局数据库名
String url=null;//连接地址
String driver=null;//数据库驱动
String userName=null;//登陆用户名
String pwd=null;//登陆密码 private Connection conn = null; //数据库连接
private ArrayList stmtBuffer = null;//存放在此连接上建立的STATEMENT
private int stmtCount = 0; //每个连接上建立的STATEMENT的数目
private boolean isUsing = false; //连接是否已经在使用
public static final int MAX_STMT_COUNT=250;//允许在一个物理连接上建立的STATEMENT的最大数目 public MyConnection() {
if (stmtBuffer == null)
stmtBuffer = new ArrayList(0);
init();
conn=connectToDB(); System.out.println("Now connection count is:"+(++MyPocket.conCt));
}
/**
* 初始化连接远程数据库的各种配置
*/
private void init(){
/*
dbHost="127.0.0.1";
dbPort=1521;
serviceName="myOra";
url="jdbc:oracle:thin:@"+dbHost+":"+dbPort+":"+serviceName;
driver="oracle.jdbc.driver.OracleDriver";
userName="sinboy";
pwd="sinboy";
*/
Properties props = new Properties();
try {
props.load(new FileInputStream("conf\\database.properties"));
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement(); //得到数据库的登陆用户名和密码
if (name.equals("username")) {
userName=props.getProperty(name);
continue;
}
if(name.equals("password")){
pwd=props.getProperty(name);
continue;
}
//得到数据库驱动
if(name.equals("driver")){
driver=props.getProperty(name);
continue;
}
//得到数据库主机的URL
if(name.equals("url")){
url=props.getProperty(name);
continue;
}
} //while
}
catch(IOException e){
String err="从数据库配置文件中读取相关信息时出错:"+
"\n"+e+
"\n请检查conf\\database.properties文件是存在";
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err); } }
/**
* 连接远程数据库
* @return 连接成功返回TRUE
*/
private Connection connectToDB(){
Connection conn=null;
try{
Class.forName(driver);
conn = DriverManager.getConnection(url, userName, pwd);
if(conn!=null)
{
String str="建立和远程数据库的连接!"+
"\n"+driver+
"\n"+url+
"\n"+userName+","+pwd;
MyPocket.myPrint(str,false);
MyPocket.log("\\logs\\log.txt",str); }
}catch(SQLException e){ String err= "无法建立和远程数据库的连接!"+
"\n"+driver+
"\n"+url+
"\n"+userName+","+pwd+
"\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
catch(ClassNotFoundException e){
String err="没有发现驱动:\n"+
driver+"\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
return conn;
} /**
* 为客户端访问数据库创建一个新的物理连接.
* @return
*/
public Connection getConn() {
if(conn==null)
{
init();
conn=connectToDB(); }
return conn;
} /**
* 返回一个物理连接上的STATEMENT
* 为一个新的客户端创建一个新的STATEMENT,如果此时在一个CONNECTION上建立的连接的
* STATEMENT已经超出规定的最大数目,则返回NULL.
* @return
*/
public Statement getStmt() {
if(conn!=null && stmtCount<MAX_STMT_COUNT)
{
try{
Statement stmt = null;
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
changeStmtCount(1);
if(stmtBuffer==null)
stmtBuffer=new ArrayList(0);
stmtBuffer.add(stmt);
return stmt;
}catch(SQLException e){
String err="在一个物理连接上为客户端创建一个STATEMENT时出错:\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
return null;
} public int stmtCount() {
return stmtCount;
} public synchronized void changeStmtCount(int step) {
stmtCount += step;
} public void setIsUsing(boolean isUsing) {
this.isUsing = isUsing;
} public boolean isUsing() {
return isUsing;
} /**
* 把指定的已经使用完毕的STATEMENT关闭,并从STMTBUFFER中清除掉.同时把STATEMENT的数目
* 相应的减一.
* @param st 已经使用完毕要关闭的STATEMENT
*/
public synchronized void closeStmt(Statement st){
Statement stmt=null;
if(st!=null && stmtBuffer!=null){
for(int i=0;i<stmtBuffer.size();i++){
stmt=(Statement)stmtBuffer.get(i);
if(stmt.equals(st)){
try{ System.err.println("关闭连接:"+conn.toString()+
"上的STATEMENT"+stmt.toString() );
System.out.println("总共关闭了STMT:"+(++MyPocket.myct));
stmt.close();
}catch(SQLException e){
String err="在关闭连接池中的一个连接上的STATEMENT时出错:\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
System.err.println("stmtBuffer.size:"+stmtBuffer.size()+" i:"+i);
stmtBuffer.remove(i);
changeStmtCount(-1);
break;
}
}
}
} /**
* 关闭和数据库的连接.
* 首先要关闭在此连接上的所有的STATEMENT,然后再关闭物理连接。
*/
public synchronized void closeConn() {
Statement stmt=null; try{
if (conn != null) {
if (stmtCount > 0) {
while (stmtBuffer.size() > 0) {
stmt = (Statement) stmtBuffer.get(0);
stmt.close();
stmtBuffer.remove(0);
}
conn.close(); }
}
}catch(SQLException e){
String err="在关闭一个和数据库的物理连接时出现异常:\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
}
import java.util.ArrayList;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
/**
* <p>Title: GPS小用户服务器</p>
* <p>Description:把查询数据库返回的标准结果记录集转换成自定义的容器中。
* 访问的方式和RESULTSET的尽量完全一样。 </p>
* <p>Copyright: Copyright (c) 2003.12.26</p>
* <p>Company: YUTONG</p>
* @author SINBOY
* @version 1.0
*/public class MyResultSet {
private ArrayList myRs=null;//存放访问数据库返回的结果记录集
private ArrayList myRow=null;//存放访问数据库返回的一行结果记录集
private ArrayList oneResult=null;//存放访问数据库返回的一个结果记录 private int cols=0;//记录集的列数
private int rows=0;//记录集的行数
private int currentRow=-1;//当前行 public MyResultSet(ResultSet rs){
if(rs!=null){
try{
/**
* 得到行数和列数
*/
ResultSetMetaData rsMeta=rs.getMetaData();
cols=rsMeta.getColumnCount();
rs.last();
rows=rs.getRow(); if (myRs == null)
myRs = new ArrayList(rows);
/**
* 把结果导出到自定义的容器中.
* colName:列的名称
* value:对应的值
*/
String colName=null;
String value=null;
rs.beforeFirst();
while(rs.next()) { myRow = new ArrayList(cols);
for (int i = 1; i <=cols; i++){
oneResult=new ArrayList(1);
colName=rsMeta.getColumnName(i);
value=rs.getString(i);
oneResult.add(0,colName);
oneResult.add(1,value); myRow.add(oneResult);
}
myRs.add(myRow); }
}catch(SQLException e){
String err="在从标准RESULTSET结果记录集中导出数据到自定义"+
"的ARRAYLIST容器中时出错:\n"+e;
MyPocket.myPrint(err,true);
MyPocket.log("\\logs\\error.txt",err);
}
}
} /**
* 根据列名得到它对应的值
* @param colName 列名
* @return 列值
*/
public String getString(String colName){
String value=null;
ArrayList oneResult=null; if(colName!=null && currentRow>=0){
if(myRs!=null && myRs.size()>currentRow){
myRow = (ArrayList) myRs.get(currentRow);
for (int i = 0; i < cols; i++) {
oneResult = (ArrayList) myRow.get(i);
if ( ( (String) oneResult.get(0)).toUpperCase().equals(colName.toUpperCase() )) {
value = (String) oneResult.get(1);
break;
}
}
}
}
return value;
} /**
* 根据列序号得到它对应的值
* @param col 列的序号
* @return 列值
*/
public String getString(int col){
String value=null;
ArrayList oneResult=null; if(col>=0){
myRow=(ArrayList)myRs.get(currentRow);
oneResult=(ArrayList)myRow.get(col);
if(oneResult!=null)
value=(String)oneResult.get(1); }
return value; } public int cols(){
return cols;
} public int rows(){
return rows;
}
public boolean next(){
currentRow++;
if(currentRow<rows)
return true;
else
return false; }
}
package gpsstdserver;
import java.io.*;
import java.net.*;
import java.util.Date;
public class ConPoolTest extends Thread{
String name=null;
Socket sck=null;
public ConPoolTest(String name){
super(name);
this.name=name; start();
}
public void run(){
try{ AccessDB accdb=null;
MyResultSet rs=null;
for(int i=0;i<50;i++){
accdb=AccessDB.getInstance();
rs=accdb.queryDB("select * from usermsg");
while(rs.next())
MyPocket.myPrint(name+"_"+i+"\n"+rs.getString("userName"),false); sleep(1);
}
/*
BufferedReader in=new BufferedReader(new InputStreamReader(
sck.getInputStream()));
while((msg=in.readLine())!=null)
System.out.println("msg:"+msg);
sleep(100000);
*/
} catch(InterruptedException e){}
}
public static void main(String argv[]) { for(int i=0;i<200;i++)
{
ConPoolTest test=new ConPoolTest("test"+i);
}}}数据库的配置方件database.properties
#数据库驱动
driver=oracle.jdbc.driver.OracleDriver
#ORACLE数据库URL
url=jdbc:oracle:thin:@192.168.0.205:1521:myOra
#ORACLE数据库登陆用户名
username=sinboy
#登陆密码
password=sinboy
我的想法可能还不太成熟,希望大家多支持,此源程序大家要觉得还能用,可以无尝使用,不过谁要是有了更好的主意,请贴出来供大家分享,共同提高。
数据库访问的模板你可以参考一下spring framework,如果你需要一个
orm,看看hibernate吧。
可以使用工厂模式+单例模式
或者门面模式+单例模式结合
客户段无需关心实现细节!!!
我使用的应该是单例模式,public class AccessDB这里应该改成private class AccessDB{}miwoo(鱼鱼羊)说的东西我还不懂,只不过前几天刚刚发现的BIBERNATE的主页,收藏了下来。抽时间我会好好学习一下。fantasyCoder(牛仔+T恤)
能不能提供一个比较完整的实例?有一期的程序员杂志上好象发表过这方面的东西,不过我觉得还不够详细。 tanghuan() ( )
能不能把你修正之后的代码贴上来?
都要保存到list里吗?
10个人同时查询每人5000条就是50000条
你这个玩意,在大数据量的时候能撑得住吗?其实jdbc2.0已经支持连接池了还有必要写连接池吗?
大量使用statement,那么preparestatement呢?
如果和特定的数据库相关的操作呢?
想法太简单了吧