監(jiān)理公司管理系統(tǒng) | 工程企業(yè)管理系統(tǒng) | OA系統(tǒng) | ERP系統(tǒng) | 造價咨詢管理系統(tǒng) | 工程設計管理系統(tǒng) | 簽約案例 | 購買價格 | 在線試用 | 手機APP | 產(chǎn)品資料
X 關閉

熱門數(shù)據(jù)庫JDBC驅動試用心得

申請免費試用、咨詢電話:400-8352-114

文章來源:泛普軟件

一、引言

無論是初級還是中高級技術人員,面對著各式各樣的數(shù)據(jù)庫平臺層出不窮和眾多的操作系統(tǒng)功能不斷升級,難免會眼花繚亂。特別是當系統(tǒng)面臨升級,無論操作平臺還是數(shù)據(jù)庫平臺,甚至架構都可能需要更替的時候,如何才能抵住眾說紛紜,把握好你的選擇。幸運的是,利用Java技術可以將這些不同種別的數(shù)據(jù)庫平臺和操作系統(tǒng)無縫地連接起來,真正地做到“集百家之長而為我所用”。

本文將通過一組真實的案例來向讀者介紹如何做到簡單地使用JDBC驅動來實現(xiàn)在不同的操作系統(tǒng)下存取幾款較為熱門的數(shù)據(jù)庫平臺。

特別是對JavaDB這款支持嵌入式模式的純Java數(shù)據(jù)庫的開發(fā)過程進行了詳細分析和展望。希望讀者能做到舉一反三,引入更多的數(shù)據(jù)庫平臺的應用。

二、評測框架

1.操作系統(tǒng)平臺和數(shù)據(jù)庫平臺

實例涉及到的操作系統(tǒng)是MS Windows XP + SP2和SUN Solaris 8,數(shù)據(jù)庫平臺有:MS Access 2000(以下簡稱Access),MS SQL Server 2000(以下簡稱SQL Server),My SQL,Oracle和Java DB(J2SE 1.6.0中綁定)。

對于XP平臺,可以安裝以上5種數(shù)據(jù)庫平臺。而對于Solaris,只可以安裝My SQL和Java DB兩種。

2.使用平臺搭建

(1)安裝支持對應操作系統(tǒng)的JDK(http://java.sun.com/javase/downloads/index.jsp)。注意:如果是Solaris操作系統(tǒng)還必須選擇對應的CPU類型,本案例中選用的是支持SPARC的JDK版本(jdk-6-solaris-sparc.sh)。在XP系統(tǒng)中安裝的JDK Update3版本的JDK(jdk-6u3-windows-i586-p.exe),保證該版本中已經(jīng)綁定Java DB。

(2)設置JAVA_HOME,PATH和CLASSPATH等環(huán)境變量。以便正常編譯和運行Java代碼。

(3)下載My SQL Connector/J驅動,并將其中的mysql-connector-java-5.1.0-bin.jar文件(其中5.1.0為驅動版本號)添加到CLASSPATH變量中。需要說明的是,該驅動文件中包含兩種JDBC驅動,一種是mm.mysql,一種是mysql普通JDBC驅動。兩者都可以使用。

(4)將包含Java DB和Oracle的驅動文件加入到CLASSPATH中。分別為derby.jar和classes12.jar。都可以在相應的產(chǎn)品安裝目錄中找到。

通過上述的配置之后,我們就可以開始在XP系統(tǒng)和Solaris系統(tǒng)中對各類數(shù)據(jù)庫平臺進行使用了。

三、試用準備

1.簡化JDBC函數(shù)

為了方便開發(fā)人員的使用,作者提煉出以下簡化后的常用JDBC函數(shù):

這些函數(shù)基本上已經(jīng)滿足大部分的使用,初級開發(fā)人員按照函數(shù)的調用步驟就可以實現(xiàn)通過JDBC驅動與各種數(shù)據(jù)庫平臺進行交互了。

如果用戶對數(shù)據(jù)庫操作的效率比較關注,那么還有3組比較重要的,也是常用的JDBC函數(shù),分別是:

(1)事務處理函數(shù):setAutoCommit/commit/rollback

(2)批處理函數(shù):addBatch/execBatch

(3)語句預處理函數(shù):prepareStatement

對于大多數(shù)開發(fā)人員,只需要知道其用法含義即可,深層次的探索和分析可能需要另外的篇幅來說明,因此作者在此不再贅述。

實際上,上述基本函數(shù)的定義,大部分都是對JDK中JDBC函數(shù)的封裝,讀者也可以通過JDBC的文檔進行相關的查閱。關鍵代碼參見全文末尾附錄部分。

2.數(shù)據(jù)庫表定義

作為試用,作者并沒有定義很復雜的數(shù)據(jù)庫表,以下是測試用數(shù)據(jù)表結構:

create table user_info(

ui_id varchar(64),

ui_passwd varchar(64),

ui_real_name varchar(64), primary key(ui_id));

3.試用思路

比較簡單,就是通過上述不同類型的JDBC驅動來連接各種數(shù)據(jù)庫平臺,然后向已經(jīng)初始化的數(shù)據(jù)表插入10000條記錄,再逐條讀取,并記錄其各個步驟的執(zhí)行耗費。

四、試用過程

1.平臺選擇

作者選擇了MS Windows XP和Solaris兩種平臺。其中只有MySQL,JavaDB和Oracle(連接遠程服務器)既可在Windows平臺進行了測試,也可在Solaris平臺下進行了測試。兩個系統(tǒng)下的測試代碼和框架完全相同。

2.使用JDBC驅動連接數(shù)據(jù)庫

(1)Access數(shù)據(jù)庫

通過JDBC驅動連接Access數(shù)據(jù)庫最常用的是采用建立ODBC數(shù)據(jù)源(DSN)的方式進行,但是本測試中采用的是通過數(shù)據(jù)庫連接字符串避開了手工建立DSN的部分。以下是關鍵代碼:

final String connectStr =

“jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=./TestDB.mdb”;

……

if( (conn = FoolDB.openDB(connectStr, null, null)) == null)

用過ADO的讀者可能一眼就看出來了,上述的連接字符串中的內容和ADO很相似。事實上,作者就是為了避開建立DNS而嘗試套用了ADO的連接字符串,結果嘗試通過了!

(2)SQL Server數(shù)據(jù)庫

需要說明的,對于SQL Server的測試沒有采用Microsoft提供的SQL Server專用的JDBC驅動,還是通過借鑒ADO的連接字符串形式,沿用了JDK自帶的JdbcOdbc驅動。

final String connectStr =

“jdbc:odbc:Driver={SQL Server};Server=.;Database=master;UID=sa;PWD=121fs”;

……

if( (conn = FoolDB.openDB(connectStr, null, null)) == null)

注意:用戶名和密碼已經(jīng)包含到連接字符串中。

SUN公司提供的SQL Server的JDBC驅動的版本應該比較陳舊,所以可能導致在操作數(shù)據(jù)庫功能支持和效率方面比當前新的JDBC驅動要差一些。Microsoft提供的SQL Server JDBC驅動類名為:“com.microsoft.jdbc.sqlserver.SQLServerDriver”,連接字符串形如:“jdbc:microsoft:sqlserver://hostname:port;DataBaseName=dbname”。

(3)MySQL數(shù)據(jù)庫

眾所周知,MySQL數(shù)據(jù)庫既可以在Windows可以在Solaris平臺運行,而且執(zhí)行效率也深得業(yè)界的好評。本試例中連接MySQL使用的是MySQL專用驅動(在第一部分已經(jīng)詳述,在MySQL官方網(wǎng)頁有很多的支持文檔),以下是關鍵代碼:

final String connectStr = “jdbc:mysql://localhost/phome”; 

final String userName = “root”; //

final String passwd = ““;

……

if( (conn = FoolDB.openDB(connectStr, userName, passwd)) == null)

在本地連接時,主機名可以使用“l(fā)ocalhost”,但如果連接遠程主機時,必須換成該遠程主機的IP,而phome是MySQL數(shù)據(jù)庫名稱。

(4)Oracle數(shù)據(jù)庫

Oracle提供了thin和oci兩種類型的驅動,本測試中使用thin類型JDBC驅動。

final String connectStr = “jdbc:oracle:thin:@WBS:1521/oracle088”;

final String userName = “test”;

final String passwd = “test”;

其中“WBS:1521/oracle088”為Oracle服務器的SID。

(5)Java DB

值得一提的,Java DB是由Apache Software Foundation主要參與開發(fā)的一個數(shù)據(jù)庫(DB)項目,SUN在JDK1.6.0中將其進行了綁定,它是一款名副其實的純Java代碼開發(fā)的數(shù)據(jù)庫平臺??梢灾С諷erver/Client也可以支持嵌入式運行模式,本實例中主要采用了嵌入式模式(Embedded)進行操作:

final String connectStr = “jdbc:derby:FoolDB”;

……

if( (conn = FoolDB.openDB(connectStr, null, null)) == null)

其中FoolDB是在初始化過程中,使用連接字符串“jdbc:derby:FoolDB;create=true”進行創(chuàng)建的。創(chuàng)建的結果是:在當前目錄中創(chuàng)建一個名為FoolDB的目錄,該目錄又中包含log,seg0和tmp這3個文件夾,而數(shù)據(jù)庫內容以多文件的方式存放于seg0目錄中。

注意:數(shù)據(jù)庫一旦創(chuàng)建之后,就無需再次創(chuàng)建了。

3.設置數(shù)據(jù)庫事務方式

當數(shù)據(jù)庫連接成功之后,需要設定連接的事務方式(前提是該數(shù)據(jù)庫平臺支持事務處理)為非自動提交,因為JDBC函數(shù)默認為自動提交。

提交過于頻繁,就會使數(shù)據(jù)庫操作的效率較低。特別是對于Oracle這種絕對支持事務處理的數(shù)據(jù)平臺而言,設置是否自動提交對系統(tǒng)的效率將有很大的影響。

4.采用批處理方式插入記錄

同樣一個考慮效率的操作,循環(huán)地執(zhí)行操作語句(Insert,Update)也會增加很多不必要地開銷。試例中采用了批量處理的方式,通過這種方式將要進行的操作先進行匯總,再批量提交執(zhí)行。這樣就可以獲得較高的執(zhí)行效率。

//Insert records 

for(int i = 0; i < RECORD_COUNT; ++i)

{

//Add each operation to batch

if(FoolDB.addBatch(execStat, “insert into user_info values('guest”

+ Integer.toString(i + 1)

+ “', '666666', '我是中國人')”) == false)

……

FoolDB.execBatch(execStat); //Execute batch operations

FoolDB.commit(conn);

FoolDB.setAutoCommit(conn, true);

這種批處理的方式,可以視同預處理,通過統(tǒng)合批量的操作來減少與數(shù)據(jù)庫的交互頻率,也減少數(shù)據(jù)庫訪問IO設備的頻率,從而也可獲得較高的效率。

5.使用行游標讀取記錄字段

記錄插入完畢之后,通過執(zhí)行查詢語句來獲取數(shù)據(jù)集。然后再通過簡化函數(shù)moveNext來逐行讀取結果集的記錄行:

//Select from table 

String sql = "select * from user_info";

if( (queryRS = FoolDB.openQuery(queryStat, sql)) == null)

{

}

while(FoolDB.moveNext(queryRS) == true)

{

//Field ui_id, text(64) type

FoolDB.getFieldByName(queryRS, “ui_id”);

//Field ui_passwd, text(64) type

FoolDB.getFieldByName(queryRS, “ui_passwd”);

//Field ui_real_name, text(64) type

FoolDB.getFieldByName(queryRS, “ui_real_name”);

}

實際上,moveNext的函數(shù)名也來源于ADO(在作者看來,JDBC和ADO的應用方式是相同的)。

6.關閉數(shù)據(jù)庫

這里主要對以嵌入式模式運行的JavaDB的關閉進行說明,其他數(shù)據(jù)庫的關閉,直接采用簡化后的關閉函數(shù)(closeDB)即可。

在嵌入式模式,應用程序退出時就必須關閉數(shù)據(jù)庫。但是如果應用程序關閉數(shù)據(jù)庫失敗,當JVM退出時不會對該未被關閉的連接進行檢查,這樣就占用了數(shù)據(jù)庫的連接資源,就會影響后續(xù)的連接執(zhí)行效率。所以Apache Derby的建議是采用URL的方式顯示地關閉數(shù)據(jù)庫。以下是關鍵代碼:

FoolDB.closeDB(conn); //Close connection 

if(framework.equals("embedded") == true) //If in embedded mode

{

//Use URL to shutdown Derby

if(FoolDB.openDB("jdbc:derby:;shutdown=true", null, null) == null)

{

//If shutdown failure means that Derby already shutdown

isShutdownOk = true;

}

if (isShutdownOk == false) //Not shutdown normally

{

System.out.println("Derby shutdown NG.");

}

}

注意:關閉和判斷Derby數(shù)據(jù)庫是否正常關閉的連接字符串中是不包含數(shù)據(jù)庫名的。

 

7.記錄各步驟操作的時間戳

以上的操作中,在各個步驟之間添加了時間戳,以此來記錄各個數(shù)據(jù)庫平臺的執(zhí)行耗費。

五、結果及分析

在對試用結果進行評價之前,讀者需要考慮各款數(shù)據(jù)庫平臺的特點,而不能簡單地從執(zhí)行時間的長短來進行判斷,以下是筆者根據(jù)開發(fā)經(jīng)驗總結出的需要注意的地方:

(1)要保證JDBC驅動和數(shù)據(jù)庫平臺的連接是無縫的。例如Oracle和JavaDB數(shù)據(jù)庫本身就是由Java開發(fā),其JDBC驅動和數(shù)據(jù)庫平臺的連接可以做到完全無縫,這樣可以充分體現(xiàn)出該款數(shù)據(jù)庫平臺的特性。反之,Access和SQL Server與對應的JdbcOdbc驅動之間的耦合可能就不如與ADO驅動那么吻合,那么這些數(shù)據(jù)平臺的很多特性就無法通過這些JDBC驅動得以體現(xiàn)。之前我們也提到,Microsoft專門有提供MS SQL Server的JDBC驅動,數(shù)據(jù)庫與這種“對口”的JDBC驅動的耦合肯定要超過JdbcOdbc這種通用型的驅動。

(2)數(shù)據(jù)庫平臺要有良好的可移植性。換句話說就是數(shù)據(jù)庫跨操作系統(tǒng)的性能。在這些方面Oracle,MySQL和JavaDB就要比Access和SQL Server有明顯優(yōu)勢,它們不僅可以支持Windows平臺而且也支持Solaris和Linux平臺。而且數(shù)據(jù)庫平臺的可移植很大程度也決定了應用系統(tǒng)的可移植性。

(3)數(shù)據(jù)庫平臺要支持應用的多樣化(需求彈性)。數(shù)據(jù)庫平臺應該不僅可以對應傳統(tǒng)的C/S,B/S模式,而且還可以擴展為三層的,甚至是多層的模式,或者支持嵌入式系統(tǒng)的應用。顯而易見,本身使用Java開發(fā)的Oracle和JavaDB在這些方面就具有得天獨厚的優(yōu)勢。而且JavaDB還支持嵌入式應用,這樣以來數(shù)據(jù)庫的應用空間就更為廣闊了。

所以基于以上幾點的考慮,我們就可以得出初步的意向:

(1)對于一般的中小型的C/S和B/S架構,MySQL可以說是我們當前首選。它在跨平臺和執(zhí)行效率方面表現(xiàn)得相當?shù)某錾?/p>

(2)對于那些對系統(tǒng)構架彈性要求比較高的系統(tǒng),可以選擇Oracle平臺,并結合EJB規(guī)范進行搭建系統(tǒng)構架無疑將是很好的選擇。

(3)選用JavaDB進行嵌入式平臺開發(fā)似乎是不錯的主意。由于現(xiàn)在很多嵌入式設備中都嵌入了Java內核,JavaDB也就可以得以應用了,嵌入式設備與其他系統(tǒng)共享數(shù)據(jù)的接口就變得及其簡單。

(4)如果只在Windows平臺進行開發(fā)的中小型系統(tǒng),用Access或者SQL Server平臺也不妨是一種簡單快捷的途徑。

六、結束語

通過前兩部分的說明,相信大家對JDBC的使用應該有相當部分的了解和收獲。即使作為初學者,通過簡化后的JDBC函數(shù)和固定的試用方式,就可以實現(xiàn)通過JSP頁面,Java Applet或者是Java Application等程序來訪問各種類型的數(shù)據(jù)庫平臺了。即使是在本文中沒有提到的其他數(shù)據(jù)庫平臺,例如:IBM的DB2,Solaris 10中綁定的PostgreSQL數(shù)據(jù)庫。

尤其的,對于中高級技術人員而言,也可以通過這幾種熱門的數(shù)據(jù)庫平臺在不同操作系統(tǒng)下的使用案例得到一定的參考。

其中,特別是介紹了對嵌入式數(shù)據(jù)庫的使用,相信也一定開闊了大家的視野和應用范圍,畢竟嵌入式系統(tǒng)的應用在目前也是如火如荼。在后續(xù)的實際開發(fā)中筆者會將更多的心得體會和大家一起分享。

七、附錄:

1.主要FoolDB函數(shù)參考

 

//Get a conn to special database. 

public static Connection openDB(final String url, final String user, final String passwd)

{

try

{

return (DriverManager.getConnection(url, user, passwd) );

}

catch (SQLException CONNECT_FAILURE)

{

}

}

//Get a statement object that can be used for query (read only)

public static Statement getQueryStat(final Connection conn)

{

try

{

return (conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

ResultSet.CONCUR_READ_ONLY) );

}

catch(SQLException CREATE_QUERY_STATEMENT)

{

}

}

//Get a statement object that can be used for update (can write)

public static Statement getExecStat(final Connection conn)

{

try

{

return (conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,

ResultSet.CONCUR_UPDATABLE) );

}

catch(SQLException CREATE_EXEC_STATEMENT)

{

}

}

//Execute SQL statement, and get the result set.

public static ResultSet openQuery(final Statement stat, final String sql)

{

try

{

return (stat.executeQuery(sql) );

}

catch(SQLException OPEN_QUERY)

{

}

}

//Get the rows cout of result set.

//The result set type should be ResultSet type is TYPE_SCROLL_SENSITIVE.

public static int getRowsCount(ResultSet rs)

{

try

{

int rowsCount = 0;

//Backup current row no.

int rowNo = rs.getRow();

//Locate last row

rs.last();

//Get the rows count

rowsCount = rs.getRow();

//Return back original row

if(rowNo < 1) //before first row

{

rs.beforeFirst();

}

else //

{

rs.absolute(rowNo);

}

return (rowsCount);

}

catch(SQLException GET_ROWS_COUNT_FAILURE)

{

}

}

//Get the columns count of resut set.

public static int getColsCount(final ResultSet rs)

{

try

{

ResultSetMetaData rsmd = rs.getMetaData();

return (rsmd.getColumnCount() );

}

catch(SQLException GET_COLS_COUNT_FAILURE)

{

}

}

//Get special column name.

//Note: The index of column base 1, but not 0.

public static String getColName(final ResultSet rs, final int colIndex)

{

try

{

ResultSetMetaData rsmd = rs.getMetaData();

return (rsmd.getColumnName(colIndex) );

}

catch(SQLException GET_COL_NAME_FAILURE)

{

}

}

//Move the cursor of result set to next row

public static boolean moveNext(ResultSet rs)

{

try

{

return (rs.next() );

}

catch(SQLException MOVE_NEXT_FAILURE)

{

}

}

//Get the retValue of cell by special row number and column number

//The result set type should be ResultSet type is TYPE_SCROLL_SENSITIVE.

//Note: The index of row and column all base 1, but no 0.

public static Object getValueAt(ResultSet rs, final int rowIndex, final int colIndex)

{

if( (rowIndex < 1) || (colIndex < 1) )

{

return (null);

}

try

{

//Backup current row no.

int rowNo = rs.getRow();

Object retValue = null;

//Locate to special row

rs.absolute(rowIndex);

//Get retValue

retValue = rs.getObject(colIndex);

//Return back origianl row

rs.absolute(rowNo);

return (retValue);

}

catch(SQLException GET_VALUE_FAILURE)

{

}

}

//Get the retValue of cell by special row number and field name

//The result set type should be ResultSet type is TYPE_SCROLL_SENSITIVE.

//Note: The index of row and column all base 1, but no 0.

public static Object getFieldByName(ResultSet rs, final int rowIndex, final String fieldName)

{

if( (rowIndex < 1) || (fieldName.equals("") == true) )

{

return (null);

}

try

{

//Backup current row no.

int rowNo = rs.getRow();

Object retValue = null;

//Locate to special row

rs.absolute(rowNo);

//Get retValue

retValue = rs.getObject(fieldName);

//Return back origianl row no.

rs.absolute(rowNo);

return (retValue);

}

catch(SQLException GET_FIELD_BY_NAME_FAILURE)

{

}

}

//Get the retValue of cell within current row by special field name

//The result set type should be ResultSet type is TYPE_SCROLL_SENSITIVE.

//Note: The index of row and column all base 1, but no 0.

public static Object getFieldByName(final ResultSet rs, final String fieldName)

{

if( (isBOF(rs) == true) || (isEOF(rs) == true) )

{

return (null);

}

try

{

return (rs.getObject(fieldName) );

}

catch(SQLException GET_FIELD_BY_NAME_FAILURE)

{

}

}

//Get the retValue of cell within current row by special column index

//The result set type should be ResultSet type is TYPE_SCROLL_SENSITIVE.

//Note: The index of row and column all base 1, but no 0.

public static Object getFieldByIndex(final ResultSet rs, final int columnIndex)

{

if( (columnIndex < 1) || (isBOF(rs) == true) || (isEOF(rs) == true) )

{

return (null);

}

try

{

return (rs.getObject(columnIndex) );

}

catch(SQLException GET_FIELD_BY_INDEX_FAILURE)

{

}

}

(it168)

發(fā)布:2007-04-22 09:24    編輯:泛普軟件 · xiaona    [打印此頁]    [關閉]
相關文章:
西安OA系統(tǒng)
聯(lián)系方式

成都公司:成都市成華區(qū)建設南路160號1層9號

重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務大廈18樓

咨詢:400-8352-114

加微信,免費獲取試用系統(tǒng)

QQ在線咨詢

泛普西安OA快博其他應用

西安OA軟件 西安OA新聞動態(tài) 西安OA信息化 西安OA快博 西安OA行業(yè)資訊 西安軟件開發(fā)公司 西安門禁系統(tǒng) 西安物業(yè)管理軟件 西安倉庫管理軟件 西安餐飲管理軟件 西安網(wǎng)站建設公司