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

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

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

文章來源:泛普軟件

一、引言

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

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

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

二、評測框架

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)安裝支持對應(yīng)操作系統(tǒng)的JDK(http://java.sun.com/javase/downloads/index.jsp)。注意:如果是Solaris操作系統(tǒng)還必須選擇對應(yī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)設(shè)置JAVA_HOME,PATH和CLASSPATH等環(huán)境變量。以便正常編譯和運行Java代碼。

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

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

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

三、試用準(zhǔn)備

1.簡化JDBC函數(shù)

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

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

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

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

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

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

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

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

2.?dāng)?shù)據(jù)庫表定義

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

create table user_info(

ui_id varchar(64),

ui_passwd varchar(64),

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

3.試用思路

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

四、試用過程

1.平臺選擇

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

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

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

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

final String connectStr =

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

……

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

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

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

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

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驅(qū)動的版本應(yīng)該比較陳舊,所以可能導(dǎo)致在操作數(shù)據(jù)庫功能支持和效率方面比當(dāng)前新的JDBC驅(qū)動要差一些。Microsoft提供的SQL Server JDBC驅(qū)動類名為:“com.microsoft.jdbc.sqlserver.SQLServerDriver”,連接字符串形如:“jdbc:microsoft:sqlserver://hostname:port;DataBaseName=dbname”。

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

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

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”,但如果連接遠(yuǎn)程主機時,必須換成該遠(yuǎn)程主機的IP,而phome是MySQL數(shù)據(jù)庫名稱。

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

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

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

final String userName = “test”;

final String passwd = “test”;

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

(5)Java DB

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

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

……

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

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

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

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

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

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

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

同樣一個考慮效率的操作,循環(huán)地執(zhí)行操作語句(Insert,Update)也會增加很多不必要地開銷。試?yán)胁捎昧伺刻幚淼姆绞?,通過這種方式將要進(jìn)行的操作先進(jìn)行匯總,再批量提交執(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);

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

5.使用行游標(biāo)讀取記錄字段

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

//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的應(yīng)用方式是相同的)。

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

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

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

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.");

}

}

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

 

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

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

五、結(jié)果及分析

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

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

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

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

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

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

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

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

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

六、結(jié)束語

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

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

其中,特別是介紹了對嵌入式數(shù)據(jù)庫的使用,相信也一定開闊了大家的視野和應(yīng)用范圍,畢竟嵌入式系統(tǒng)的應(yī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    [打印此頁]    [關(guān)閉]
相關(guān)文章:
西安OA系統(tǒng)
聯(lián)系方式

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

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

咨詢:400-8352-114

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

QQ在線咨詢

泛普西安OA快博其他應(yīng)用

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