|
級別: 初級
劉冬 (winter.lau@163.com), 一直使用J2EE從事移動業(yè)務方面的開發(fā)
2003 年 10 月 28 日
本文中,作者向大家介紹了一種輕量級得關系數據庫系統(tǒng),它可以在建立應用系統(tǒng)的演示版時代替大型數據庫系統(tǒng)的功能,使應用系統(tǒng)的演示版更加輕便。
有這個必要嗎?
我相信很多人看到這個題目都會提出這樣一個問題:為什么要嵌入數據庫到應用程序中,有這個必要嗎?是的,數據庫的出現就是為了將應用邏輯以及數據存儲邏輯分開,如果把二者又揉合在一起豈不是違背了這樣一個初衷?但是設想一下這樣一個情況:當我們發(fā)布一個應用程序時我們希望用戶可以非常簡單的把它運行起來,因為有時候是用戶第一次試用你的產品并由此來決定是否采用這個產品的時候,第一感覺對用戶來講是非常重要。如果只是為了大概了解一下應用程序而需要做一大堆的前期工作,比如數據庫的安裝、配置、初始化,如果這并不是一個非常復雜的應用,那我想這么大的一堆設置工作對誰來說都是殘酷的,給用戶的第一次印象那么差,你還敢肯定他還會對這個產品感興趣嗎?
舉個例子:現在網上有很多開放源碼的門戶平臺軟件,可謂是琳瑯滿目。當我們需要選擇其中一個的時候,我想你肯定沒有那么多時間對每個軟件都一一進行深入了解,那么是什么因素決定最后選型的結果呢?在一開始你應該不會注意到每個門戶軟件的所有功能,你第一步要做的肯定是先把它運行起來感覺一下,如果你花了半天時間發(fā)現還沒有按照安裝手冊配置起來的時候,就算功能再強大你也肯定失望透頂,而且這完全不是你能力的問題,這個軟件真的糟透了。還是這個例子,我會選擇Jetspeed,它安裝夠簡單,因為它內嵌了一個數據庫,我們無需在這方面花費額外的時間。當然考慮到性能的問題你同樣可以使用其他獨立的數據庫產品,但是你在一開始會重視性能這個問題嗎?
HSQLDB數據庫是否支持標準SQL
如果你還能撐到這里或許可以說明你同意我剛才的觀點,那么我們開始吧。
用來嵌入到應用程序的數據庫引擎你肯定不會去關注它的性能怎么樣?你更關心它是否夠強大,是否支持標準的SQL語句以及是否有符合JDBC規(guī)范的驅動程序。這兩個條件也就足夠了,你還能要求什么呢?
HSQLDB支持的標準和特征: 1. 開放源碼的數據庫引擎 2. 使用標準SQL語法以及提供了JDBC驅動程序 3. 免費的數據庫引擎 4. 是一個緊湊且快速的引擎 5. 可以獨立運行或者嵌入到應用程序中 6. 設置可以在applet中使用 7. 可以自動建立索引以及使用索引 8. 支持數據庫事務操作 9. 允許表間聯(lián)合查詢 10. 支持引用完整性檢查 11. 支持JAVA的存儲過程以及函數 12. 可以通過SQL腳本來創(chuàng)建數據庫 13. 使用用戶名和口令來控制訪問權限 14. 兼容JDK1.1以及以上版本
這里羅列了HSQLDB最重要的一些特征,我們更關心的前幾條。已經有很多產品使用了該數據庫引擎,有如我們最開始舉例的jetspeed,同時在網站上很多關于內容管理的軟件同樣也使用了這個數據庫引擎。我們完全可以放心將它植入到我們的應用程序中。由于HSQLDB本身支持標準SQL語法以及JDBC規(guī)范,因為我們可以很方便的移植到其他的數據庫。
HSQLDB的數據存儲結構
了解HSQLDB的數據存儲結構可以更有利于我們對這個的集成。我們需要保證它不會跟我們的程序本身沖突,這也是最最基本的要求。
HSQLDB提供兩種操作模式,進程內以及客戶機服務器模式。由于我們的目的是為了嵌入因此我們只介紹進程內模式。應用該模式時數據庫的訪問只能是同一個虛擬機內。數據庫的訪問同樣是使用JDBC接口,但又無需網絡連接。運行于進程內模式的HSQLDB只能有一個數據庫,也就是說我們無法同時創(chuàng)建兩個或者兩個以上的數據庫并訪問它們。
由于HSQLDB是完全運行內存中的數據庫引擎,一旦數據庫有改變時,這些信息會保存到磁盤中,以便下次啟動的時候是最新的狀態(tài)。由于是運行于內存中,所以數據量的大小就僅僅是受限于內存的大小。由于HSQLDB并不會應用在生產環(huán)境中,因此這個倒不是我們非常關心的問題。
啟動一個HSQLDB實例的時候需要給它制定一個目錄用于存放數據庫的一些文件,這些文件包括$DBNAME.data,$DBNAME.properties,$DBNAME.script(其中$DBNAME為數據庫名)這三個文件分別是數據文件;配置文件以及數據庫創(chuàng)建的腳本文件,但是實際上數據文件內容是空的,所有的數據都寫在腳本文件中。
開始嵌入HSQLDB數據庫引擎
為了測試HSQLDB我們需要兩個類,一個是數據庫的服務線程,另外一個則是測試入口類,這兩個類代碼如下:
package lius.demo.hsqldb;
/*
* Created on 2003-10-5 by Liudong
* /
import java.io.*;
import java.sql.*;
import org.hsqldb.*;
/**
* HSQLDB數據庫引擎測試類
* @author Liudong
*/
public class HsqldbDemo {
//數據庫名稱
public final static String DATABASE_NAME = "hsqltest";
//數據庫端口缺省為9001
public final static int PORT = 9001;
/**
* 測試程序入口
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String path = "data";
File f = new File(path);
if(!f.exists())
f.mkdirs();
HsqlDBManager hsqldb = new HsqlDBManager(path);
hsqldb.setDatabaseName(DATABASE_NAME);
hsqldb.setPort(PORT);
new Thread(hsqldb).start();
System.out.println("數據庫服務已啟動");
//開始測試
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = null;
try{
//連接數據庫
Class.forName("org.hsqldb.jdbcDriver");
conn = DriverManager.getConnection("jdbc:hsqldb:hsql://localhost","sa","");
//創(chuàng)建表
sql = "CREATE TABLE USER(ID INTEGER,NAME VARCHAR(50),MOBILE CHAR(12))";
ps = conn.prepareStatement(sql);
ps.executeUpdate();
//插入數據
sql = "INSERT INTO user VALUES(?,?,?)";
ps = conn.prepareStatement(sql);
ps.setInt(1, 1);
ps.setString(2, "Winter Lau");
ps.setString(3,"13912345678");
ps.executeUpdate();
//查詢數據
ps = conn.prepareStatement("SELECT * FROM user");
rs = ps.executeQuery();
while(rs.next()){
System.out.println("ID:"+rs.getInt("id"));
System.out.println("NAME:"+rs.getString("name"));
System.out.println("MOBILE:"+rs.getString("mobile"));
}
}
finally{
if(rs!=null)
rs.close();
if(ps!=null)
ps.close();
if(conn!=null)
conn.close();
}
//退出程序
System.exit(0);
}
}
/**
* 數據庫服務線程
* @author Liudong
*/
class HsqlDBManager implements Runnable {
String dataPath;
String databaseName = "test";
int port = -1;
/**
* 構造函數,需要一個數據路徑的參數
* 該參數必須為物理存在的路徑
* @param dataPath
*/
public HsqlDBManager(String dataPath) {
this.dataPath = dataPath;
if(!this.dataPath.endsWith(File.separator))
this.dataPath += File.separator;
this.dataPath += databaseName;
}
/
* 線程入口
* @see java.lang.Runnable#run()
*/
public void run() {
String[] args = null;
if(port!=-1)
args = new String[]{"-database",dataPath,"-port",port+""};
else
args = new String[]{"-database",dataPath};
//調用HSQLDB的服務入口
Server.main(args);
}
public String getDatabaseName() {
return databaseName;
}
public String getDataPath() {
return dataPath;
}
public void setDatabaseName(String string) {
databaseName = string;
}
public void setDataPath(String string) {
dataPath = string;
}
public int getPort() {
return port;
}
public void setPort(int i) {
port = i;
}
}
|
運行該程序需要一個hsqldb.jar的包文件,其運行結果如下所示
數據庫服務已啟動
server.properties not found, using command line or default properties
Opening database: data\\test
HSQLDB server 1.7.1 is running
Use SHUTDOWN to close normally. Use [Ctrl]+[C] to abort abruptly
Tue Oct 14 10:34:52 CST 2003 Listening for connections ...
ID:1
NAME:Winter Lau
MOBILE:13912345678
|
由于同一個HSQLDB實例只能有一個數據庫,所以我們在程序中的JDBC URL中并無需制定數據庫名。通過上面的代碼我們發(fā)現作為客戶端在使用HSQLDB提供的數據庫服務跟其他的商業(yè)數據庫并沒有什么區(qū)別,也就是說HSQLDB提供了基本的數據庫功能,包括一些數據類型都非常完善。但是還是那句話,如果你不想惹麻煩的話請不要將HSQLDB用于生產環(huán)境,僅僅把它當成一個過渡環(huán)境只是為了方便開發(fā)一些DEMO程序用。
參考資料
HSQLDB網址 http://hsqldb./
關于作者
|