作者-- joinme
這是一篇基礎性文章,主要介紹了jdbc在流行數據庫(sql server,oracle)方面的應用。但是都是個人觀點,所以不能保證完全正確,僅供參考,如果有不同意見可以在評論中指出,我會做相應的修改。:)
一般情況下,直接用jdbc等東西連數據庫時,比較常用連數據庫的代碼可能是:
?? private Connection conn
?? private String poolURL = "";
?? private String driverName ="";
?? private String user=""
?? private String pass="";
?? private DBConnProxy Proxy; //自己寫的class,起控制數據庫訪問作用
public Object getConn()
????{
??????try
?????????? {
?????????????????????? Properties??prop=new Properties();
?????????????????????? prop.setProperty("user",user);
?????????????????????? prop.setProperty("password",pass);
?????????????????????? Driver mydriver=(Driver)Class.forName(driverName).newInstance();
?????????????????????? conn = mydriver.connect(poolURL,prop);//或者conn = mydriver.connect(poolURL,null);具體什么時候用我還的請教高手。
??????????????????/*
???????????????? 或者:
????????????????Class.forName(driverName);
????????????????conn=DriverManager.getConnection(poolURL, user, pass);
????????????????*/
?????????? }
??????catch ( Exception??e )
??{
?? System.out.println("打開數據庫出錯\n" + e.getMessage());
??}
????????????????if(!Proxy.getDB() ){
??????????????????this.Close()
??????????????????return null;
????????????????}
?? return conn;
??????}
其中的 driverName,poolURL,user,pass都可以通過讀取 xml文件或普通屬性文件獲取。而是連sqlserver還是oracle就只是改改配置就可以了。
它們都可以用 sun.jdbc.odbc.JdbcOdbcDriver 來連。對應poolURL="jdbc:odbc:test",user,pass略
也可以用自己特有的:
sqlserver:weblogic.jdbc.mssqlserver4.Driver (網上下) 對應poolURL="jdbc:weblogic:mssqlserver4:ceic@127.0.0.1" //ceic是數據庫名,127.0.0.1是數據源位置,可以是遠程的數據庫,user,pass略
oracle:oracle.jdbc.driver.OracleDriver (class12.zip,裝了oracle就應該有了) 對應jdbc:oracle:thin:scott/tiger@10.1.103.234:1521:sp"??scott/tiger連接身份的用戶名/密碼,10.1.103.234,數據源ip,1521:端口(默認是1521). sp指向數據庫名user,pass略
如果用的weblogic配的數據庫連接,可以通過
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("forceicdatasource"); //forceicdatasource是配的datasource.也可以通過和上面統一的方法來調用。
weblogic:weblogic.jdbc.pool.Driver //driverName
對應的poolURL="jdbc:weblogic:pool:poolname" //poolname是在weblogic中配的jdbc類型的connections pool的名字。user,pass是weblogic用戶(administrators用戶組中的用戶)的用戶名和密碼。(如果不是用DriverManager就用不上,"conn = mydriver.connect(poolURL,null);"就是在這種情況下可以用。我在weblogic 6.1下測試通過)
綜上說的,可以看出,大多數數據庫連接都可以通過配置 屬性文件 來靈活的獲取。(移植起來很是方便,并且對應用基本沒有什么影響,當然也可以夸平臺)所以我可以通過動態讀取屬性文件來解決。
private String javaHome = System.getProperty("java.home");
private final String FS = System.getProperty("file.separator");
private String path = javaHome+FS+"db.properties"; //把db.properties放在系統屬性java.home下,一般是jdk目錄下的 jre目錄里。
public boolean getInfo(){
File file=new java.io.File(path);
Properties pro=new Properties();
boolean readsucced;
try{
InputStream in=new BufferedInputStream(new FileInputStream(file));
pro.load(in);
driverName=pro.getProperty("driverName");
poolURL=pro.getProperty("poolURL") ;
user=pro.getProperty("user") ;
pass=pro.getProperty("pass") ;
//自己把它們trim()掉。我就偷懶不寫了。
readsucced=true;
}catch(Exception e){System.out.println("讀取屬性文件出錯");readsucced=false;}
return readsucced;
}
不過一般只用讀一次就可以了。所以可以把它放在 static{}塊里,也可以放在構造器里面(然后和放在靜態連接池,如果是單獨的應用,應該把getInfo()作為靜態類和數據庫連接類分開)。
public DBConn() {
setDBConnProxy(ProxyFactory.DefaultType );//設定連接proxy,控制數據庫連接頻率,可能會犧牲效力,不過在防止惡意破壞上有點作用,自己寫的畢竟趕不上weblogic的連接池了。所以只好做點小的防范措施.如果是用weblogic配的連接池,可以直接在proxyFactory里面加個什么都不做的proxy.
getInfo();
}
屬性文件db.properties內容如下:
driverName=sun.jdbc.odbc.JdbcOdbcDriver
poolURL=jdbc:odbc:test
user=sa
pass=1234Q_Q5678
自己可以耕具實際情況去更改屬性文件。
注: getConn()方法返回的是 Object,是不同的數據庫連接有不同的擴展應用,比如oracle的就有針對clob,blob的應用(用class12.zip的情況下),普通的connection不能滿足,所以可以通過在應用中把getConn()返回的Object轉化成OracleConnection來用。(個人觀點,不知道有沒有更好的解決方法)
上面寫的這么多,可能只對新手有點用處,在j2ee風行的今天已經很落伍了,還希望高手指出問題一起討論(還沒有有關于mysql的連接辦法,沒有做過,希望有人能補充上來)。
————————————————————————————————————————
使用JAVA中的動態代理實現數據庫連接池
數據庫連接池在編寫應用服務是經常需要用到的模塊,太過頻繁的連接數據庫對服務性能來講是一個瓶頸,使用緩沖池技術可以來消除這個瓶頸。我們可以在互聯網上找到很多關于數據庫連接池的源程序,但是都發現這樣一個共同的問題:這些連接池的實現方法都不同程度地增加了與使用者之間的耦合度。很多的連接池都要求用戶通過其規定的方法獲取數據庫的連接,這一點我們可以理解,畢竟目前所有的應用服務器取數據庫連接的方式都是這種方式實現的。但是另外一個共同的問題是,它們同時不允許使用者顯式的調用Connection.close()方法,而需要用其規定的一個方法來關閉連接。這種做法有兩個缺點:
第一:改變了用戶使用習慣,增加了用戶的使用難度。
首先我們來看看一個正常的數據庫操作過程:
int executeSQL(String sql) throws SQLException
{
????????Connection conn = getConnection();????????//通過某種方式獲取數據庫連接
????????PreparedStatement ps = null;
????????int res = 0;
????????try{
????????????????ps = conn.prepareStatement(sql);
????????????????res = ps.executeUpdate();
}finally{
try{
ps.close();
}catch(Exception e){}
try{
????????conn.close();//
}catch(Exception e){}
}
return res;
}
使用者在用完數據庫連接后通常是直接調用連接的方法close來釋放數據庫資源,如果用我們前面提到的連接池的實現方法,那語句conn.close()將被某些特定的語句所替代。
第二:使連接池無法對之中的所有連接進行獨占控制。由于連接池不允許用戶直接調用連接的close方法,一旦使用者在使用的過程中由于習慣問題直接關閉了數據庫連接,那么連接池將無法正常維護所有連接的狀態,考慮連接池和應用由不同開發人員實現時這種問題更容易出現。
綜合上面提到的兩個問題,我們來討論一下如何解決這兩個要命的問題。
首先我們先設身處地的考慮一下用戶是想怎么樣來使用這個數據庫連接池的。用戶可以通過特定的方法來獲取數據庫的連接,同時這個連接的類型應該是標準的java.sql.Connection。用戶在獲取到這個數據庫連接后可以對這個連接進行任意的操作,包括關閉連接等。
通過對用戶使用的描述,怎樣可以接管Connection.close方法就成了我們這篇文章的主題。
為了接管數據庫連接的close方法,我們應該有一種類似于鉤子的機制。例如在Windows編程中我們可以利用Hook API來實現對某個Windows API的接管。在JAVA中同樣也有這樣一個機制。JAVA提供了一個Proxy類和一個InvocationHandler,這兩個類都在java.lang.reflect包中。我們先來看看SUN公司提供的文檔是怎么描述這兩個類的。
public interface InvocationHandler
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler.
When a method is invoked on a proxy instance,
the method invocation is encoded and dispatched to the invoke method of its invocation handler.
SUN的API文檔中關于Proxy的描述很多,這里就不羅列出來。通過文檔對接口InvocationHandler的描述我們可以看到當調用一個Proxy實例的方法時會觸發Invocationhanlder的invoke方法。從JAVA的文檔中我們也同時了解到這種動態代理機制只能接管接口的方法,而對一般的類無效,考慮到java.sql.Connection本身也是一個接口由此就找到了解決如何接管close方法的出路。
首先,我們先定義一個數據庫連接池參數的類,定義了數據庫的JDBC驅動程序類名,連接的URL以及用戶名口令等等一些信息,該類是用于初始化連接池的參數,具體定義如下:
public class ConnectionParam implements Serializable
{
????????private String driver;????????????????????????????????//數據庫驅動程序
????????private String url;????????????????????????????????????????//數據連接的URL
????????private String user;????????????????????????????????????????//數據庫用戶名
????????private String password;????????????????????????????????//數據庫密碼
????????private int minConnection = 0;????????????????//初始化連接數
????????private int maxConnection = 50;????????????????//最大連接數
????????private long timeoutValue = 600000;//連接的最大空閑時間
????????private long waitTime = 30000;????????????????//取連接的時候如果沒有可用連接最大的等待時間
其次是連接池的工廠類ConnectionFactory,通過該類來將一個連接池對象與一個名稱對應起來,使用者通過該名稱就可以獲取指定的連接池對象,具體代碼如下:
/**
* 連接池類廠,該類常用來保存多個數據源名稱合數據庫連接池對應的哈希
* @author liusoft
*/
public class ConnectionFactory
{
????????//該哈希表用來保存數據源名和連接池對象的關系表
????????static Hashtable connectionPools = null;
????????static{
????????????????connectionPools = new Hashtable(2,0.75F);
????????}
????????/**
???????? * 從連接池工廠中獲取指定名稱對應的連接池對象
???????? * @param dataSource????????連接池對象對應的名稱
???????? * @return DataSource????????返回名稱對應的連接池對象
???????? * @throws NameNotFoundException????????無法找到指定的連接池
???????? */
????????public static DataSource lookup(String dataSource)
????????????????throws NameNotFoundException
????????{
????????????????Object ds = null;
????????????????ds = connectionPools.get(dataSource);
????????????????if(ds == null || !(ds instanceof DataSource))
????????????????????????throw new NameNotFoundException(dataSource);
????????????????return (DataSource)ds;
????????}
????????/**
???????? * 將指定的名字和數據庫連接配置綁定在一起并初始化數據庫連接池
???????? * @param name????????????????對應連接池的名稱
???????? * @param param????????連接池的配置參數,具體請見類ConnectionParam
???????? * @return DataSource????????如果綁定成功后返回連接池對象
???????? * @throws NameAlreadyBoundException????????一定名字name已經綁定則拋出該異常
???????? * @throws ClassNotFoundException????????????????無法找到連接池的配置中的驅動程序類
???????? * @throws IllegalAccessException????????????????連接池配置中的驅動程序類有誤
???????? * @throws InstantiationException????????????????無法實例化驅動程序類
???????? * @throws SQLException????????????????????????????????無法正常連接指定的數據庫
???????? */
????????public static DataSource bind(String name, ConnectionParam param)
????????????????throws NameAlreadyBoundException,ClassNotFoundException,
????????????????????????????????IllegalAccessException,InstantiationException,SQLException
????????{
????????????????DataSourceImpl source = null;
????????????????try{
????????????????????????lookup(name);
????????????????????????throw new NameAlreadyBoundException(name);
????????????????}catch(NameNotFoundException e){
????????????????????????source = new DataSourceImpl(param);
????????????????????????source.initConnection();
????????????????????????connectionPools.put(name, source);
????????????????}
????????????????return source;
????????}
????????/**
???????? * 重新綁定數據庫連接池
???????? * @param name????????????????對應連接池的名稱
???????? * @param param????????連接池的配置參數,具體請見類ConnectionParam
???????? * @return DataSource????????如果綁定成功后返回連接池對象
???????? * @throws NameAlreadyBoundException????????一定名字name已經綁定則拋出該異常
???????? * @throws ClassNotFoundException????????????????無法找到連接池的配置中的驅動程序類
???????? * @throws IllegalAccessException????????????????連接池配置中的驅動程序類有誤
???????? * @throws InstantiationException????????????????無法實例化驅動程序類
???????? * @throws SQLException????????????????????????????????無法正常連接指定的數據庫
???????? */
????????public static DataSource rebind(String name, ConnectionParam param)
????????????????throws NameAlreadyBoundException,ClassNotFoundException,
????????????????????????????????IllegalAccessException,InstantiationException,SQLException
????????{
????????????????try{
????????????????????????unbind(name);
????????????????}catch(Exception e){}
????????????????return bind(name, param);
????????}
????????/**
???????? * 刪除一個數據庫連接池對象
???????? * @param name
???????? * @throws NameNotFoundException
???????? */
????????public static void unbind(String name) throws NameNotFoundException
????????{
????????????????DataSource dataSource = lookup(name);
????????????????if(dataSource instanceof DataSourceImpl){
????????????????????????DataSourceImpl dsi = (DataSourceImpl)dataSource;
????????????????????????try{
????????????????????????????????dsi.stop();
????????????????????????????????dsi.close();
????????????????????????}catch(Exception e){
????????????????????????}finally{
????????????????????????????????dsi = null;
????????????????????????}
????????????????}
????????????????connectionPools.remove(name);
????????}
????????
}
ConnectionFactory主要提供了用戶將將連接池綁定到一個具體的名稱上以及取消綁定的操作。使用者只需要關心這兩個類即可使用數據庫連接池的功能。下面我們給出一段如何使用連接池的代碼:
????????String name = "pool";
????????String driver = " sun.jdbc.odbc.JdbcOdbcDriver ";
????????String url = "jdbc:odbc:datasource";
????????ConnectionParam param = new ConnectionParam(driver,url,null,null);
????????param.setMinConnection(1);
????????param.setMaxConnection(5);
????????param.setTimeoutValue(20000);
????????ConnectionFactory.bind(name, param);
????????System.out.println("bind datasource ok.");
????????//以上代碼是用來登記一個連接池對象,該操作可以在程序初始化只做一次即可
????????//以下開始就是使用者真正需要寫的代碼
????????DataSource ds = ConnectionFactory.lookup(name);
????????try{
????????????????for(int i=0;i<10;i++){
????????????????????????Connection conn = ds.getConnection();
????????????????????????try{
????????????????????????????????testSQL(conn, sql);
????????????????????????}finally{
????????????????????????????????try{
????????????????????????????????????????conn.close();
????????????????????????????????}catch(Exception e){}
????????????????????????}
????????????????}
????????}catch(Exception e){
????????????????e.printStackTrace();
????????}finally{
????????????????ConnectionFactory.unbind(name);
????????????????System.out.println("unbind datasource ok.");
????????????????System.exit(0);
????????}
從使用者的示例代碼就可以看出,我們已經解決了常規連接池產生的兩個問題。但是我們最最關心的是如何解決接管close方法的辦法。接管工作主要在ConnectionFactory中的兩句代碼:
source = new DataSourceImpl(param);
source.initConnection();
DataSourceImpl是一個實現了接口javax.sql.DataSource的類,該類維護著一個連接池的對象。由于該類是一個受保護的類,因此它暴露給使用者的方法只有接口DataSource中定義的方法,其他的所有方法對使用者來說都是不可視的。我們先來關心用戶可訪問的一個方法getConnection
/**
* @see javax.sql.DataSource#getConnection(String,String)
*/
????????public Connection getConnection(String user, String password) throws SQLException
????????{
????????????????//首先從連接池中找出空閑的對象
????????????????Connection conn = getFreeConnection(0);
????????????????if(conn == null){
????????????????????????//判斷是否超過最大連接數,如果超過最大連接數
????????????????????????//則等待一定時間查看是否有空閑連接,否則拋出異常告訴用戶無可用連接
????????????????????????if(getConnectionCount() >= connParam.getMaxConnection())
????????????????????????????????conn = getFreeConnection(connParam.getWaitTime());
????????????????????????else{//沒有超過連接數,重新獲取一個數據庫的連接
????????????????????????????????connParam.setUser(user);
????????????????????????????????connParam.setPassword(password);
????????????????????????????????Connection conn2 = DriverManager.getConnection(connParam.getUrl(),
????????????????????????????????user, password);
????????????????????????????????//代理將要返回的連接對象
????????????????????????????????_Connection _conn = new _Connection(conn2,true);
????????????????????????????????synchronized(conns){
????????????????????????????????????????conns.add(_conn);
????????????????????????????????}
????????????????????????????????conn = _conn.getConnection();
????????????????????????}
????????????????}
????????????????return conn;
????????}
????????/**
???????? * 從連接池中取一個空閑的連接
???????? * @param nTimeout????????如果該參數值為0則沒有連接時只是返回一個null
???????? * 否則的話等待nTimeout毫秒看是否還有空閑連接,如果沒有拋出異常
???????? * @return Connection
???????? * @throws SQLException
???????? */
????????protected synchronized Connection getFreeConnection(long nTimeout)
????????????????throws SQLException
????????{
????????????????Connection conn = null;
????????????????Iterator iter = conns.iterator();
????????????????while(iter.hasNext()){
????????????????????????_Connection _conn = (_Connection)iter.next();
????????????????????????if(!_conn.isInUse()){
????????????????????????????????conn = _conn.getConnection();
????????????????????????????????_conn.setInUse(true);????????????????????????????????
????????????????????????????????break;
????????????????????????}
????????????????}
????????????????if(conn == null && nTimeout > 0){
????????????????????????//等待nTimeout毫秒以便看是否有空閑連接
????????????????????????try{
????????????????????????????????Thread.sleep(nTimeout);
????????????????????????}catch(Exception e){}
????????????????????????conn = getFreeConnection(0);
????????????????????????if(conn == null)
????????????????????????????????throw new SQLException("沒有可用的數據庫連接");
????????????????}
????????????????return conn;
????????}
DataSourceImpl類中實現getConnection方法的跟正常的數據庫連接池的邏輯是一致的,首先判斷是否有空閑的連接,如果沒有的話判斷連接數是否已經超過最大連接數等等的一些邏輯。但是有一點不同的是通過DriverManager得到的數據庫連接并不是及時返回的,而是通過一個叫_Connection的類中介一下,然后調用_Connection.getConnection返回的。如果我們沒有通過一個中介也就是JAVA中的Proxy來接管要返回的接口對象,那么我們就沒有辦法截住Connection.close方法。
終于到了核心所在,我們先來看看_Connection是如何實現的,然后再介紹是客戶端調用Connection.close方法時走的是怎樣一個流程,為什么并沒有真正的關閉連接。
/**
* 數據連接的自封裝,屏蔽了close方法
* @author Liudong
*/
class _Connection implements InvocationHandler
{
????????private final static String CLOSE_METHOD_NAME = "close";
????????private Connection conn = null;
????????//數據庫的忙狀態
????????private boolean inUse = false;
????????//用戶最后一次訪問該連接方法的時間
????????private long lastAccessTime = System.currentTimeMillis();
????????
????????_Connection(Connection conn, boolean inUse){
????????????????this.conn = conn;
????????????????this.inUse = inUse;
????????}
????????/**
???????? * Returns the conn.
???????? * @return Connection
???????? */
????????public Connection getConnection() {
????????????????//返回數據庫連接conn的接管類,以便截住close方法
????????????????Connection conn2 = (Connection)Proxy.newProxyInstance(
????????????????????????conn.getClass().getClassLoader(),
????????????????????????conn.getClass().getInterfaces(),this);
????????????????return conn2;
????????}
????????/**
???????? * 該方法真正的關閉了數據庫的連接
???????? * @throws SQLException
???????? */
????????void close() throws SQLException{
????????????????//由于類屬性conn是沒有被接管的連接,因此一旦調用close方法后就直接關閉連接
????????????????conn.close();
????????}
????????/**
???????? * Returns the inUse.
???????? * @return boolean
???????? */
????????public boolean isInUse() {
????????????????return inUse;
????????}
????????/**
???????? * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
???????? */
????????public Object invoke(Object proxy, Method m, Object[] args)
????????????????throws Throwable
????????{
????????????????Object obj = null;
????????????????//判斷是否調用了close的方法,如果調用close方法則把連接置為無用狀態
????????????????if(CLOSE_METHOD_NAME.equals(m.getName()))
????????????????????????setInUse(false);????????????????
????????????????else
????????????????????????obj = m.invoke(conn, args);????????
????????????????//設置最后一次訪問時間,以便及時清除超時的連接
????????????????lastAccessTime = System.currentTimeMillis();
????????????????return obj;
????????}
????????????????
????????/**
???????? * Returns the lastAccessTime.
???????? * @return long
???????? */
????????public long getLastAccessTime() {
????????????????return lastAccessTime;
????????}
????????/**
???????? * Sets the inUse.
???????? * @param inUse The inUse to set
???????? */
????????public void setInUse(boolean inUse) {
????????????????this.inUse = inUse;
????????}
}
一旦使用者調用所得到連接的close方法,由于用戶的連接對象是經過接管后的對象,因此JAVA虛擬機會首先調用_Connection.invoke方法,在該方法中首先判斷是否為close方法,如果不是則將代碼轉給真正的沒有被接管的連接對象conn。否則的話只是簡單的將該連接的狀態設置為可用。到此您可能就明白了整個接管的過程,但是同時也有一個疑問:這樣的話是不是這些已建立的連接就始終沒有辦法真正關閉?答案是可以的。我們來看看ConnectionFactory.unbind方法,該方法首先找到名字對應的連接池對象,然后關閉該連接池中的所有連接并刪除掉連接池。在DataSourceImpl類中定義了一個close方法用來關閉所有的連接,詳細代碼如下:
????????/**
???????? * 關閉該連接池中的所有數據庫連接
???????? * @return int 返回被關閉連接的個數
???????? * @throws SQLException
???????? */
????????public int close() throws SQLException
????????{
????????????????int cc = 0;
????????????????SQLException excp = null;
????????????????Iterator iter = conns.iterator();
????????????????while(iter.hasNext()){
????????????????????????try{
????????????????????????????????((_Connection)iter.next()).close();
????????????????????????????????cc ++;
????????????????????????}catch(Exception e){
????????????????????????????????if(e instanceof SQLException)
????????????????????????????????????????excp = (SQLException)e;
????????????????????????}
????????????????}
????????????????if(excp != null)
????????????????????????throw excp;
????????????????return cc;
????????}
該方法一一調用連接池中每個對象的close方法,這個close方法對應的是_Connection中對close的實現,在_Connection定義中關閉數據庫連接的時候是直接調用沒有經過接管的對象的關閉方法,因此該close方法真正的釋放了數據庫資源。
以上文字只是描述了接口方法的接管,具體一個實用的連接池模塊還需要對空閑連接的監控并及時釋放連接,詳細的代碼請參照附件。
參考資料:
http://java.sun.com
JAVA的官方網站
from-ibm developer
——————————————————————————————————————————
這是一篇基礎性文章,主要介紹了jdbc在流行數據庫(sql server,oracle)方面的應用。但是都是個人觀點,所以不能保證完全正確,僅供參考,如果有不同意見可以在評論中指出,我會做相應的修改。:)
一般情況下,直接用jdbc等東西連數據庫時,比較常用連數據庫的代碼可能是:
?? private Connection conn
?? private String poolURL = "";
?? private String driverName ="";
?? private String user=""
?? private String pass="";
?? private DBConnProxy Proxy; //自己寫的class,起控制數據庫訪問作用
public Object getConn()
????{
??????try
?????????? {
?????????????????????? Properties??prop=new Properties();
?????????????????????? prop.setProperty("user",user);
?????????????????????? prop.setProperty("password",pass);
?????????????????????? Driver mydriver=(Driver)Class.forName(driverName).newInstance();
?????????????????????? conn = mydriver.connect(poolURL,prop);//或者conn = mydriver.connect(poolURL,null);具體什么時候用我還的請教高手。
??????????????????/*
???????????????? 或者:
????????????????Class.forName(driverName);
????????????????conn=DriverManager.getConnection(poolURL, user, pass);
????????????????*/
?????????? }
??????catch ( Exception??e )
??{
?? System.out.println("打開數據庫出錯\n" + e.getMessage());
??}
????????????????if(!Proxy.getDB() ){
??????????????????this.Close()
??????????????????return null;
????????????????}
?? return conn;
??????}
其中的 driverName,poolURL,user,pass都可以通過讀取 xml文件或普通屬性文件獲取。而是連sqlserver還是oracle就只是改改配置就可以了。
它們都可以用 sun.jdbc.odbc.JdbcOdbcDriver 來連。對應poolURL="jdbc:odbc:test",user,pass略
也可以用自己特有的:
sqlserver:weblogic.jdbc.mssqlserver4.Driver (網上下) 對應poolURL="jdbc:weblogic:mssqlserver4:ceic@127.0.0.1" //ceic是數據庫名,127.0.0.1是數據源位置,可以是遠程的數據庫,user,pass略
oracle:oracle.jdbc.driver.OracleDriver (class12.zip,裝了oracle就應該有了) 對應jdbc:oracle:thin:scott/tiger@10.1.103.234:1521:sp"??scott/tiger連接身份的用戶名/密碼,10.1.103.234,數據源ip,1521:端口(默認是1521). sp指向數據庫名user,pass略
如果用的weblogic配的數據庫連接,可以通過
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("forceicdatasource"); //forceicdatasource是配的datasource.也可以通過和上面統一的方法來調用。
weblogic:weblogic.jdbc.pool.Driver //driverName
對應的poolURL="jdbc:weblogic:pool:poolname" //poolname是在weblogic中配的jdbc類型的connections pool的名字。user,pass是weblogic用戶(administrators用戶組中的用戶)的用戶名和密碼。(如果不是用DriverManager就用不上,"conn = mydriver.connect(poolURL,null);"就是在這種情況下可以用。我在weblogic 6.1下測試通過)
綜上說的,可以看出,大多數數據庫連接都可以通過配置 屬性文件 來靈活的獲取。(移植起來很是方便,并且對應用基本沒有什么影響,當然也可以夸平臺)所以我可以通過動態讀取屬性文件來解決。
private String javaHome = System.getProperty("java.home");
private final String FS = System.getProperty("file.separator");
private String path = javaHome+FS+"db.properties"; //把db.properties放在系統屬性java.home下,一般是jdk目錄下的 jre目錄里。
public boolean getInfo(){
File file=new java.io.File(path);
Properties pro=new Properties();
boolean readsucced;
try{
InputStream in=new BufferedInputStream(new FileInputStream(file));
pro.load(in);
driverName=pro.getProperty("driverName");
poolURL=pro.getProperty("poolURL") ;
user=pro.getProperty("user") ;
pass=pro.getProperty("pass") ;
//自己把它們trim()掉。我就偷懶不寫了。
readsucced=true;
}catch(Exception e){System.out.println("讀取屬性文件出錯");readsucced=false;}
return readsucced;
}
不過一般只用讀一次就可以了。所以可以把它放在 static{}塊里,也可以放在構造器里面(然后和放在靜態連接池,如果是單獨的應用,應該把getInfo()作為靜態類和數據庫連接類分開)。
public DBConn() {
setDBConnProxy(ProxyFactory.DefaultType );//設定連接proxy,控制數據庫連接頻率,可能會犧牲效力,不過在防止惡意破壞上有點作用,自己寫的畢竟趕不上weblogic的連接池了。所以只好做點小的防范措施.如果是用weblogic配的連接池,可以直接在proxyFactory里面加個什么都不做的proxy.
getInfo();
}
屬性文件db.properties內容如下:
driverName=sun.jdbc.odbc.JdbcOdbcDriver
poolURL=jdbc:odbc:test
user=sa
pass=1234Q_Q5678
自己可以耕具實際情況去更改屬性文件。
注: getConn()方法返回的是 Object,是不同的數據庫連接有不同的擴展應用,比如oracle的就有針對clob,blob的應用(用class12.zip的情況下),普通的connection不能滿足,所以可以通過在應用中把getConn()返回的Object轉化成OracleConnection來用。(個人觀點,不知道有沒有更好的解決方法)
上面寫的這么多,可能只對新手有點用處,在j2ee風行的今天已經很落伍了,還希望高手指出問題一起討論(還沒有有關于mysql的連接辦法,沒有做過,希望有人能補充上來)。
————————————————————————————————————————
使用JAVA中的動態代理實現數據庫連接池
數據庫連接池在編寫應用服務是經常需要用到的模塊,太過頻繁的連接數據庫對服務性能來講是一個瓶頸,使用緩沖池技術可以來消除這個瓶頸。我們可以在互聯網上找到很多關于數據庫連接池的源程序,但是都發現這樣一個共同的問題:這些連接池的實現方法都不同程度地增加了與使用者之間的耦合度。很多的連接池都要求用戶通過其規定的方法獲取數據庫的連接,這一點我們可以理解,畢竟目前所有的應用服務器取數據庫連接的方式都是這種方式實現的。但是另外一個共同的問題是,它們同時不允許使用者顯式的調用Connection.close()方法,而需要用其規定的一個方法來關閉連接。這種做法有兩個缺點:
第一:改變了用戶使用習慣,增加了用戶的使用難度。
首先我們來看看一個正常的數據庫操作過程:
int executeSQL(String sql) throws SQLException
{
????????Connection conn = getConnection();????????//通過某種方式獲取數據庫連接
????????PreparedStatement ps = null;
????????int res = 0;
????????try{
????????????????ps = conn.prepareStatement(sql);
????????????????res = ps.executeUpdate();
}finally{
try{
ps.close();
}catch(Exception e){}
try{
????????conn.close();//
}catch(Exception e){}
}
return res;
}
使用者在用完數據庫連接后通常是直接調用連接的方法close來釋放數據庫資源,如果用我們前面提到的連接池的實現方法,那語句conn.close()將被某些特定的語句所替代。
第二:使連接池無法對之中的所有連接進行獨占控制。由于連接池不允許用戶直接調用連接的close方法,一旦使用者在使用的過程中由于習慣問題直接關閉了數據庫連接,那么連接池將無法正常維護所有連接的狀態,考慮連接池和應用由不同開發人員實現時這種問題更容易出現。
綜合上面提到的兩個問題,我們來討論一下如何解決這兩個要命的問題。
首先我們先設身處地的考慮一下用戶是想怎么樣來使用這個數據庫連接池的。用戶可以通過特定的方法來獲取數據庫的連接,同時這個連接的類型應該是標準的java.sql.Connection。用戶在獲取到這個數據庫連接后可以對這個連接進行任意的操作,包括關閉連接等。
通過對用戶使用的描述,怎樣可以接管Connection.close方法就成了我們這篇文章的主題。
為了接管數據庫連接的close方法,我們應該有一種類似于鉤子的機制。例如在Windows編程中我們可以利用Hook API來實現對某個Windows API的接管。在JAVA中同樣也有這樣一個機制。JAVA提供了一個Proxy類和一個InvocationHandler,這兩個類都在java.lang.reflect包中。我們先來看看SUN公司提供的文檔是怎么描述這兩個類的。
public interface InvocationHandler
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler.
When a method is invoked on a proxy instance,
the method invocation is encoded and dispatched to the invoke method of its invocation handler.
SUN的API文檔中關于Proxy的描述很多,這里就不羅列出來。通過文檔對接口InvocationHandler的描述我們可以看到當調用一個Proxy實例的方法時會觸發Invocationhanlder的invoke方法。從JAVA的文檔中我們也同時了解到這種動態代理機制只能接管接口的方法,而對一般的類無效,考慮到java.sql.Connection本身也是一個接口由此就找到了解決如何接管close方法的出路。
首先,我們先定義一個數據庫連接池參數的類,定義了數據庫的JDBC驅動程序類名,連接的URL以及用戶名口令等等一些信息,該類是用于初始化連接池的參數,具體定義如下:
public class ConnectionParam implements Serializable
{
????????private String driver;????????????????????????????????//數據庫驅動程序
????????private String url;????????????????????????????????????????//數據連接的URL
????????private String user;????????????????????????????????????????//數據庫用戶名
????????private String password;????????????????????????????????//數據庫密碼
????????private int minConnection = 0;????????????????//初始化連接數
????????private int maxConnection = 50;????????????????//最大連接數
????????private long timeoutValue = 600000;//連接的最大空閑時間
????????private long waitTime = 30000;????????????????//取連接的時候如果沒有可用連接最大的等待時間
其次是連接池的工廠類ConnectionFactory,通過該類來將一個連接池對象與一個名稱對應起來,使用者通過該名稱就可以獲取指定的連接池對象,具體代碼如下:
/**
* 連接池類廠,該類常用來保存多個數據源名稱合數據庫連接池對應的哈希
* @author liusoft
*/
public class ConnectionFactory
{
????????//該哈希表用來保存數據源名和連接池對象的關系表
????????static Hashtable connectionPools = null;
????????static{
????????????????connectionPools = new Hashtable(2,0.75F);
????????}
????????/**
???????? * 從連接池工廠中獲取指定名稱對應的連接池對象
???????? * @param dataSource????????連接池對象對應的名稱
???????? * @return DataSource????????返回名稱對應的連接池對象
???????? * @throws NameNotFoundException????????無法找到指定的連接池
???????? */
????????public static DataSource lookup(String dataSource)
????????????????throws NameNotFoundException
????????{
????????????????Object ds = null;
????????????????ds = connectionPools.get(dataSource);
????????????????if(ds == null || !(ds instanceof DataSource))
????????????????????????throw new NameNotFoundException(dataSource);
????????????????return (DataSource)ds;
????????}
????????/**
???????? * 將指定的名字和數據庫連接配置綁定在一起并初始化數據庫連接池
???????? * @param name????????????????對應連接池的名稱
???????? * @param param????????連接池的配置參數,具體請見類ConnectionParam
???????? * @return DataSource????????如果綁定成功后返回連接池對象
???????? * @throws NameAlreadyBoundException????????一定名字name已經綁定則拋出該異常
???????? * @throws ClassNotFoundException????????????????無法找到連接池的配置中的驅動程序類
???????? * @throws IllegalAccessException????????????????連接池配置中的驅動程序類有誤
???????? * @throws InstantiationException????????????????無法實例化驅動程序類
???????? * @throws SQLException????????????????????????????????無法正常連接指定的數據庫
???????? */
????????public static DataSource bind(String name, ConnectionParam param)
????????????????throws NameAlreadyBoundException,ClassNotFoundException,
????????????????????????????????IllegalAccessException,InstantiationException,SQLException
????????{
????????????????DataSourceImpl source = null;
????????????????try{
????????????????????????lookup(name);
????????????????????????throw new NameAlreadyBoundException(name);
????????????????}catch(NameNotFoundException e){
????????????????????????source = new DataSourceImpl(param);
????????????????????????source.initConnection();
????????????????????????connectionPools.put(name, source);
????????????????}
????????????????return source;
????????}
????????/**
???????? * 重新綁定數據庫連接池
???????? * @param name????????????????對應連接池的名稱
???????? * @param param????????連接池的配置參數,具體請見類ConnectionParam
???????? * @return DataSource????????如果綁定成功后返回連接池對象
???????? * @throws NameAlreadyBoundException????????一定名字name已經綁定則拋出該異常
???????? * @throws ClassNotFoundException????????????????無法找到連接池的配置中的驅動程序類
???????? * @throws IllegalAccessException????????????????連接池配置中的驅動程序類有誤
???????? * @throws InstantiationException????????????????無法實例化驅動程序類
???????? * @throws SQLException????????????????????????????????無法正常連接指定的數據庫
???????? */
????????public static DataSource rebind(String name, ConnectionParam param)
????????????????throws NameAlreadyBoundException,ClassNotFoundException,
????????????????????????????????IllegalAccessException,InstantiationException,SQLException
????????{
????????????????try{
????????????????????????unbind(name);
????????????????}catch(Exception e){}
????????????????return bind(name, param);
????????}
????????/**
???????? * 刪除一個數據庫連接池對象
???????? * @param name
???????? * @throws NameNotFoundException
???????? */
????????public static void unbind(String name) throws NameNotFoundException
????????{
????????????????DataSource dataSource = lookup(name);
????????????????if(dataSource instanceof DataSourceImpl){
????????????????????????DataSourceImpl dsi = (DataSourceImpl)dataSource;
????????????????????????try{
????????????????????????????????dsi.stop();
????????????????????????????????dsi.close();
????????????????????????}catch(Exception e){
????????????????????????}finally{
????????????????????????????????dsi = null;
????????????????????????}
????????????????}
????????????????connectionPools.remove(name);
????????}
????????
}
ConnectionFactory主要提供了用戶將將連接池綁定到一個具體的名稱上以及取消綁定的操作。使用者只需要關心這兩個類即可使用數據庫連接池的功能。下面我們給出一段如何使用連接池的代碼:
????????String name = "pool";
????????String driver = " sun.jdbc.odbc.JdbcOdbcDriver ";
????????String url = "jdbc:odbc:datasource";
????????ConnectionParam param = new ConnectionParam(driver,url,null,null);
????????param.setMinConnection(1);
????????param.setMaxConnection(5);
????????param.setTimeoutValue(20000);
????????ConnectionFactory.bind(name, param);
????????System.out.println("bind datasource ok.");
????????//以上代碼是用來登記一個連接池對象,該操作可以在程序初始化只做一次即可
????????//以下開始就是使用者真正需要寫的代碼
????????DataSource ds = ConnectionFactory.lookup(name);
????????try{
????????????????for(int i=0;i<10;i++){
????????????????????????Connection conn = ds.getConnection();
????????????????????????try{
????????????????????????????????testSQL(conn, sql);
????????????????????????}finally{
????????????????????????????????try{
????????????????????????????????????????conn.close();
????????????????????????????????}catch(Exception e){}
????????????????????????}
????????????????}
????????}catch(Exception e){
????????????????e.printStackTrace();
????????}finally{
????????????????ConnectionFactory.unbind(name);
????????????????System.out.println("unbind datasource ok.");
????????????????System.exit(0);
????????}
從使用者的示例代碼就可以看出,我們已經解決了常規連接池產生的兩個問題。但是我們最最關心的是如何解決接管close方法的辦法。接管工作主要在ConnectionFactory中的兩句代碼:
source = new DataSourceImpl(param);
source.initConnection();
DataSourceImpl是一個實現了接口javax.sql.DataSource的類,該類維護著一個連接池的對象。由于該類是一個受保護的類,因此它暴露給使用者的方法只有接口DataSource中定義的方法,其他的所有方法對使用者來說都是不可視的。我們先來關心用戶可訪問的一個方法getConnection
/**
* @see javax.sql.DataSource#getConnection(String,String)
*/
????????public Connection getConnection(String user, String password) throws SQLException
????????{
????????????????//首先從連接池中找出空閑的對象
????????????????Connection conn = getFreeConnection(0);
????????????????if(conn == null){
????????????????????????//判斷是否超過最大連接數,如果超過最大連接數
????????????????????????//則等待一定時間查看是否有空閑連接,否則拋出異常告訴用戶無可用連接
????????????????????????if(getConnectionCount() >= connParam.getMaxConnection())
????????????????????????????????conn = getFreeConnection(connParam.getWaitTime());
????????????????????????else{//沒有超過連接數,重新獲取一個數據庫的連接
????????????????????????????????connParam.setUser(user);
????????????????????????????????connParam.setPassword(password);
????????????????????????????????Connection conn2 = DriverManager.getConnection(connParam.getUrl(),
????????????????????????????????user, password);
????????????????????????????????//代理將要返回的連接對象
????????????????????????????????_Connection _conn = new _Connection(conn2,true);
????????????????????????????????synchronized(conns){
????????????????????????????????????????conns.add(_conn);
????????????????????????????????}
????????????????????????????????conn = _conn.getConnection();
????????????????????????}
????????????????}
????????????????return conn;
????????}
????????/**
???????? * 從連接池中取一個空閑的連接
???????? * @param nTimeout????????如果該參數值為0則沒有連接時只是返回一個null
???????? * 否則的話等待nTimeout毫秒看是否還有空閑連接,如果沒有拋出異常
???????? * @return Connection
???????? * @throws SQLException
???????? */
????????protected synchronized Connection getFreeConnection(long nTimeout)
????????????????throws SQLException
????????{
????????????????Connection conn = null;
????????????????Iterator iter = conns.iterator();
????????????????while(iter.hasNext()){
????????????????????????_Connection _conn = (_Connection)iter.next();
????????????????????????if(!_conn.isInUse()){
????????????????????????????????conn = _conn.getConnection();
????????????????????????????????_conn.setInUse(true);????????????????????????????????
????????????????????????????????break;
????????????????????????}
????????????????}
????????????????if(conn == null && nTimeout > 0){
????????????????????????//等待nTimeout毫秒以便看是否有空閑連接
????????????????????????try{
????????????????????????????????Thread.sleep(nTimeout);
????????????????????????}catch(Exception e){}
????????????????????????conn = getFreeConnection(0);
????????????????????????if(conn == null)
????????????????????????????????throw new SQLException("沒有可用的數據庫連接");
????????????????}
????????????????return conn;
????????}
DataSourceImpl類中實現getConnection方法的跟正常的數據庫連接池的邏輯是一致的,首先判斷是否有空閑的連接,如果沒有的話判斷連接數是否已經超過最大連接數等等的一些邏輯。但是有一點不同的是通過DriverManager得到的數據庫連接并不是及時返回的,而是通過一個叫_Connection的類中介一下,然后調用_Connection.getConnection返回的。如果我們沒有通過一個中介也就是JAVA中的Proxy來接管要返回的接口對象,那么我們就沒有辦法截住Connection.close方法。
終于到了核心所在,我們先來看看_Connection是如何實現的,然后再介紹是客戶端調用Connection.close方法時走的是怎樣一個流程,為什么并沒有真正的關閉連接。
/**
* 數據連接的自封裝,屏蔽了close方法
* @author Liudong
*/
class _Connection implements InvocationHandler
{
????????private final static String CLOSE_METHOD_NAME = "close";
????????private Connection conn = null;
????????//數據庫的忙狀態
????????private boolean inUse = false;
????????//用戶最后一次訪問該連接方法的時間
????????private long lastAccessTime = System.currentTimeMillis();
????????
????????_Connection(Connection conn, boolean inUse){
????????????????this.conn = conn;
????????????????this.inUse = inUse;
????????}
????????/**
???????? * Returns the conn.
???????? * @return Connection
???????? */
????????public Connection getConnection() {
????????????????//返回數據庫連接conn的接管類,以便截住close方法
????????????????Connection conn2 = (Connection)Proxy.newProxyInstance(
????????????????????????conn.getClass().getClassLoader(),
????????????????????????conn.getClass().getInterfaces(),this);
????????????????return conn2;
????????}
????????/**
???????? * 該方法真正的關閉了數據庫的連接
???????? * @throws SQLException
???????? */
????????void close() throws SQLException{
????????????????//由于類屬性conn是沒有被接管的連接,因此一旦調用close方法后就直接關閉連接
????????????????conn.close();
????????}
????????/**
???????? * Returns the inUse.
???????? * @return boolean
???????? */
????????public boolean isInUse() {
????????????????return inUse;
????????}
????????/**
???????? * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
???????? */
????????public Object invoke(Object proxy, Method m, Object[] args)
????????????????throws Throwable
????????{
????????????????Object obj = null;
????????????????//判斷是否調用了close的方法,如果調用close方法則把連接置為無用狀態
????????????????if(CLOSE_METHOD_NAME.equals(m.getName()))
????????????????????????setInUse(false);????????????????
????????????????else
????????????????????????obj = m.invoke(conn, args);????????
????????????????//設置最后一次訪問時間,以便及時清除超時的連接
????????????????lastAccessTime = System.currentTimeMillis();
????????????????return obj;
????????}
????????????????
????????/**
???????? * Returns the lastAccessTime.
???????? * @return long
???????? */
????????public long getLastAccessTime() {
????????????????return lastAccessTime;
????????}
????????/**
???????? * Sets the inUse.
???????? * @param inUse The inUse to set
???????? */
????????public void setInUse(boolean inUse) {
????????????????this.inUse = inUse;
????????}
}
一旦使用者調用所得到連接的close方法,由于用戶的連接對象是經過接管后的對象,因此JAVA虛擬機會首先調用_Connection.invoke方法,在該方法中首先判斷是否為close方法,如果不是則將代碼轉給真正的沒有被接管的連接對象conn。否則的話只是簡單的將該連接的狀態設置為可用。到此您可能就明白了整個接管的過程,但是同時也有一個疑問:這樣的話是不是這些已建立的連接就始終沒有辦法真正關閉?答案是可以的。我們來看看ConnectionFactory.unbind方法,該方法首先找到名字對應的連接池對象,然后關閉該連接池中的所有連接并刪除掉連接池。在DataSourceImpl類中定義了一個close方法用來關閉所有的連接,詳細代碼如下:
????????/**
???????? * 關閉該連接池中的所有數據庫連接
???????? * @return int 返回被關閉連接的個數
???????? * @throws SQLException
???????? */
????????public int close() throws SQLException
????????{
????????????????int cc = 0;
????????????????SQLException excp = null;
????????????????Iterator iter = conns.iterator();
????????????????while(iter.hasNext()){
????????????????????????try{
????????????????????????????????((_Connection)iter.next()).close();
????????????????????????????????cc ++;
????????????????????????}catch(Exception e){
????????????????????????????????if(e instanceof SQLException)
????????????????????????????????????????excp = (SQLException)e;
????????????????????????}
????????????????}
????????????????if(excp != null)
????????????????????????throw excp;
????????????????return cc;
????????}
該方法一一調用連接池中每個對象的close方法,這個close方法對應的是_Connection中對close的實現,在_Connection定義中關閉數據庫連接的時候是直接調用沒有經過接管的對象的關閉方法,因此該close方法真正的釋放了數據庫資源。
以上文字只是描述了接口方法的接管,具體一個實用的連接池模塊還需要對空閑連接的監控并及時釋放連接,詳細的代碼請參照附件。
參考資料:
http://java.sun.com
JAVA的官方網站
from-ibm developer
——————————————————————————————————————————
??1
package?dbo;
??2
import?java.sql.*;
??3
import?java.util.*;
??4
??5
public?class?DBO
??6

{
??7
????Connection?conn;
??8
????String?user="[username]";?????????????????//[password]為您連接數據庫的用戶名
??9
????String?password="[password]";?????????????//[password]為您連接數據庫的密碼
?10
?11
????public?DBO()
?12
????
{
?13
????try?
{
?14
????????????Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
?15
????????}?catch?(ClassNotFoundException?e)
?16
????????
{
?17
????????????e.printStackTrace();
?18
????????}
?19
????String?url="jdbc:odbc:BBS";
?20
????try?
{
?21
?????????conn=?DriverManager.getConnection(url);
?22
????????}?catch?(SQLException?e)
?23
????????
{
?24
????????????e.printStackTrace();
?25
????????}
?26
????}
?27
?28
/**//*
?29
///////////////////////////////Access數據庫(ODBC數據源)
?30
?31
????public?DBO()
?32
????{
?33
????try?{
?34
????????????Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
?35
????????}
?36
????????catch?(ClassNotFoundException?e)
?37
????????{
?38
????????????e.printStackTrace();
?39
????????}
?40
????String?url="jdbc:odbc:[datebase]";????????????????//[datebase]為你的數據庫名
?41
????try?{
?42
?????????conn=?DriverManager.getConnection(url,user,password);
?43
????????}?catch?(SQLException?e)
?44
????????{
?45
????????????e.printStackTrace();
?46
????????}
?47
????????}
?48
*/
?49
?50
/**//*
?51
////////////////////////Oracle8/8i/9i數據庫(thin模式)
?52
?53
????public?DBO()
?54
????{
?55
????try?{
?56
????????????Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
?57
????????}
?58
????????catch?(InstantiationException?e)
?59
????????{
?60
????????????e.printStackTrace();
?61
????????}
?62
????????catch?(IllegalAccessException?e)
?63
????????{
?64
????????????e.printStackTrace();
?65
????????}
?66
????????catch?(ClassNotFoundException?e)
?67
????????{
?68
????????????e.printStackTrace();
?69
????????}
?70
????????String?url="jdbc:oracle:thin:@localhost:[xxxx]:[datebase]";
?71
????????????????????????????????????????????????????????//[xxxx]為您的數據庫服務器端口(默認1521);[datebase]為你的數據庫名?
?72
????????try?{
?73
????????conn=?DriverManager.getConnection(url,user,password);
?74
????????}?catch?(SQLException?e)
?75
????????{
?76
????????????e.printStackTrace();
?77
????????}
?78
????}
?79
*/
?80
?81
?82
/**//*
?83
?84
//////////////////////////連接DB2數據庫
?85
public?DBO()
?86
????{
?87
????try?{
?88
????????????Class.forName("com.ibm.db2.jdbc.app.DB2Driver").newInstance();
?89
????????}
?90
????????catch?(InstantiationException?e)
?91
????????{
?92
????????????e.printStackTrace();
?93
????????}
?94
????????catch?(IllegalAccessException?e)
?95
????????{
?96
????????????e.printStackTrace();
?97
????????}
?98
????????catch?(ClassNotFoundException?e)
?99
????????{
100
????????????e.printStackTrace();
101
????????}
102
????????String?url="jdbc:db2://localhost:[xxxx]/[datebase]";
103
????????????????????????????????????????????????????????//[xxxx]為您的數據庫服務器端口(默認5000);[datebase]為你的數據庫名?
104
????try?{
105
????????conn=?DriverManager.getConnection(url,user,password);?
106
????????}
107
????????catch?(SQLException?e)
108
????????{
109
????????????e.printStackTrace();
110
????????}
111
????}
112
113
*/
114
115
/**//*
116
117
//////////////////////////Sql?Server7.0/2000數據庫
118
public?DBO()
119
????{
120
????try?{
121
????????????Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();?
122
????????}
123
????????catch?(InstantiationException?e)
124
????????{
125
????????????e.printStackTrace();
126
????????}
127
????????catch?(IllegalAccessException?e)
128
????????{
129
????????????e.printStackTrace();
130
????????}
131
????????catch?(ClassNotFoundException?e)
132
????????{
133
????????????e.printStackTrace();
134
????????}
135
????????String?url="jdbc:microsoft:sqlserver://localhost:[xxxx];DatabaseName=[datebase]";
136
????????????????????????????????????????????????//[xxxx]為您的數據庫服務器的端口(默認1433);[datebase]為你的數據庫名??
137
????try?{
138
????????conn=?DriverManager.getConnection(url,user,password);
139
????????}?catch?(SQLException?e)
140
????????{
141
????????????e.printStackTrace();
142
????????}
143
????}
144
145
*/
146
147
148
/**//*
149
//////////////////////////Sybase數據庫?
150
151
public?DBO()
152
????{
153
????try?{
154
????????Class.forName("com.sybase.jdbc.SybDriver").newInstance();?
155
????????}
156
????????catch?(InstantiationException?e)
157
????????{
158
????????????e.printStackTrace();
159
????????}
160
????????catch?(IllegalAccessException?e)
161
????????{
162
????????????e.printStackTrace();
163
????????}
164
????????catch?(ClassNotFoundException?e)
165
????????{
166
????????????e.printStackTrace();
167
????????}
168
????????String?url?="?jdbc:sybase:Tds:localhost:[xxxx]/[datebase]";????
169
????????????????????????????????????????????????????//[xxxx]為您的數據庫服務器的端口(默認5007);[datebase]為你的數據庫名
170
????????Properties?SysProps?=?System.getProperties();
171
????????SysProps.put("user","[username]");?????????????//[username]為您連接數據庫的用戶名
172
????????SysProps.put("password","[password]");????????//[password]為您連接數據庫的密碼
173
????try?{
174
????????conn=?DriverManager.getConnection(url,?SysProps);
175
????????}?catch?(SQLException?e)
176
????????{
177
????????????e.printStackTrace();
178
????????}
179
????}
180
*/
181
182
/**//*
183
//////////////////////////Informix數據庫
184
????public?DBO()
185
????{
186
????try?{
187
????????Class.forName("com.informix.jdbc.IfxDriver").newInstance();?
188
????????}
189
????????catch?(InstantiationException?e)
190
????????{
191
????????????e.printStackTrace();
192
????????}
193
????????catch?(IllegalAccessException?e)
194
????????{
195
????????????e.printStackTrace();
196
????????}
197
????????catch?(ClassNotFoundException?e)
198
????????{
199
????????????e.printStackTrace();
200
????????}
201
????????String?url="jdbc:informix-sqli://123.45.67.89:[xxxx]/[datebase]:INFORMIXSERVER=myserver;user=[username];password=[password]";?
202
????????????????????????????????????????????????//[xxxx]為您的數據庫服務器的端口(默認1533);[datebase]為您的數據庫名??
203
????try?{
204
????????conn=?DriverManager.getConnection(url);?
205
????????}?catch?(SQLException?e)
206
????????{
207
????????????e.printStackTrace();
208
????????}
209
????}
210
211
*/
212
213
/**//*
214
//////////////////////////MySQL數據庫
215
216
????public?DBO()
217
????{
218
????try?{
219
????????Class.forName("org.gjt.mm.mysql.Driver").newInstance();
220
????????}
221
????????catch?(InstantiationException?e)
222
????????{
223
????????????e.printStackTrace();
224
????????}
225
????????catch?(IllegalAccessException?e)
226
????????{
227
????????????e.printStackTrace();
228
????????}
229
????????catch?(ClassNotFoundException?e)
230
????????{
231
????????????e.printStackTrace();
232
????????}
233
????????String?url="jdbc:mysql://localhost/[datebase]?user=[username]&password=[password]&useUnicode=true&characterEncoding=[CharCoding]";
234
????????????????????????????????????????????????????//[CharCoding]為您的數據庫服務器使用的語言編碼(默認8859-1);[datebase]為您的數據庫名??
235
236
????try?{
237
????????conn=?DriverManager.getConnection(url);?
238
????????}?catch?(SQLException?e)
239
????????{
240
????????????e.printStackTrace();
241
????????}
242
????}
243
*/
244
245
/**//*
246
//////////////////PostgreSQL數據庫
247
248
249
????public?DBO()
250
????{
251
????try?{
252
????????Class.forName("org.postgresql.Driver").newInstance();
253
????????}
254
????????catch?(InstantiationException?e)
255
????????{
256
????????????e.printStackTrace();
257
????????}
258
????????catch?(IllegalAccessException?e)
259
????????{
260
????????????e.printStackTrace();
261
????????}
262
????????catch?(ClassNotFoundException?e)
263
????????{
264
????????????e.printStackTrace();
265
????????}
266
????????String?url?="jdbc:postgresql://localhost/[datebase]";
267
????????????????????????????????????????????????//[datebase]為您的數據庫名??
268
????try?{
269
????????conn=?DriverManager.getConnection(url,user,password);?
270
????????}?catch?(SQLException?e)
271
????????{
272
????????????e.printStackTrace();
273
????????}
274
????}
275
276
*/
277
278
}
279

??2

??3

??4

??5

??6



??7

??8

??9

?10

?11

?12



?13



?14

?15

?16



?17

?18

?19

?20



?21

?22

?23



?24

?25

?26

?27

?28


?29

?30

?31

?32

?33

?34

?35

?36

?37

?38

?39

?40

?41

?42

?43

?44

?45

?46

?47

?48

?49

?50


?51

?52

?53

?54

?55

?56

?57

?58

?59

?60

?61

?62

?63

?64

?65

?66

?67

?68

?69

?70

?71

?72

?73

?74

?75

?76

?77

?78

?79

?80

?81

?82


?83

?84

?85

?86

?87

?88

?89

?90

?91

?92

?93

?94

?95

?96

?97

?98

?99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115


116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148


149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182


183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213


214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245


246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279
