HsqlDb的持續化構建

在開發程序過程中,自從無意中使用了HsqlDb後,由於其速度特快,愛不釋手(“不用不知道,誰用誰知道”),將原來所使用的Sybase,Sql Anywhere, MySql全都通通扔到了一邊。在持續化構建過程中,因其尚未提供ant的第三方任務插件,因此需要清楚地瞭解在命令行下進行相應操作的方法,再通過進行轉化,進而針對其特點特作此小結。而大衆化的知識,如驅動類名(org.hsqldb.jdbcDriver),如何在Java代碼中進行連接,用戶名(默認爲”sa”)與密碼(默認爲””),“地球人都知道”,就不作詳細介紹了。

1. HsqlDb自帶工具
 org.hsqldb.util.DatabaseManager
 org.hsqldb.util.DatabaseManagerSwing
 org.hsqldb.util.Transfer
 org.hsqldb.util.QueryTool
 org.hsqldb.util.SqlTool
調用方法:java -cp hsqldb.jar org.hsqldb.util.DatabaseManager(在hsqldb.jar的當前路徑下)

2. HsqlDb的數據庫
 以文件形式存在。
 未指定文件名時,默認爲"test",會產生以下幾種文件
 test.properties
 test.script
 test.log
 test.data
 test.backup

3. HsqlDb數據庫的類型
服務器模式:允許多個連接
Server模式: jdbc:hsqldb:hsql://localhost/<dbname>
Web Server模式: jdbc:hsqldb:http://<hostname>/<dbname>
Servlet模式: 只能通過Tomcat等服務器提供服務
獨佔模式:只允許一個連接
jdbc:hsqldb:file:<dbname>
內存模式:存在於內存中,速度最快,但最後一個連接關閉或數據庫關閉時,數據丟失。
jdbc:hsqldb:mem:<dbname>

4. HsqlDb的啓動
 當服務器啓動時,如果在指定的路徑中找不到相應的數據庫名稱,會自動創建數據庫。
 未指定路徑及文件名,則在執行java命令的當前路徑下創建test數據庫

下面舉幾個例子。下載HsqlDb後,將其解壓到某個文件夾下面,假設F:\temp\hsqldb。打開一個命令行窗口,執行

F: (回車)
cd F:\temp\hsqldb (回車)

將當前路徑設爲F:\temp\hsqldb。

 執行
java -classpath ./lib/hsqldb.jar org.hsqldb.Server
啓動Server模式數據庫,則在F:\temp\hsqldb下面新建test.lck、test.txt及test.properties三個文件。此三個文件組成了名爲test的數據庫。
 執行
java -classpath ./lib/hsqldb.jar org.hsqldb.Server -database.0 adb -dbname.0 adb
在F:\temp\hsqldb下面新建adb.lck、adb.txt及adb.properties三個文件。其中,由-database.0指定的adb是存放數據庫的文件名,由-dbname.0指定的adb是對外提供連接的數據庫名稱(也稱爲別名),可用jdbc:hsqldb:hsql://localhost/adb進行連接。
 執行
java -classpath ./lib/hsqldb.jar org.hsqldb.Server -database.0 data/adb -dbname.0 adb
在F:\temp\hsqldb\data下面新建adb.lck、adb.txt及adb.properties三個文件。如果data這個文件夾不存在,會自動創建。與上面比較,存放數據庫的路徑變了,但別名未變,因此,也用jdbc:hsqldb:hsql://localhost/adb進行連接。

5. 執行SQL語句
執行SQL語句時,出於安全原因,需要在用戶根目錄(Windows XP中是C:\Documents and Settings\<username>,注意,不是”我的文檔”)下面新建一個名爲sqltool.rc文件。對於Server模式,其內容如下:

urlid localhost-sa
url jdbc:hsqldb:hsql://localhost/<dbname>
username sa
password

其中,url、username及password是我們所熟悉的數據庫連接參數,而urlid是在執行SQL語句時需要用於驗證用戶身份的id。此值可相對任意取,但在同一sqltool.rc文件中必須唯一。使用方法見下面。

5.1 通過命令行執行SQL語句

java -jar ./lib/hsqldb.jar --sql " INSERT INTO Person VALUES(1, ‘Mike’);select * from Person " localhost-sa

通過調用java命令,執行hsqldb.jar,將參數設爲--sql,表示要執行SQL語句。SQL語句在兩個以上時,用括號包圍,之間以分號隔開。SQL語句之後緊跟着的就是sqltool.rc中的urlid。這裏的urlid必須與sqltool.rc致時才能執行SQL語句。這樣可在一定程度上防範SQL注入侵犯。

5.2 通過SQL文件執行SQL語句

java -jar ./lib/hsqldb.jar localhost-sa sample.sql

sample.sql爲SQL文件名,跟在urlid之後。因其有一定特點,特列出全部內容,以便說明:

/*
$Id: sample.sql,v 1.5 2005/05/02 15:07:27 unsaved Exp $
Examplifies use of SqlTool.
PCTASK Table creation
*/

/* Ignore error for these two statements */
\c true
DROP TABLE pctasklist;
DROP TABLE pctask;
\c false

\p Creating table pctask
CREATE TABLE pctask (
id integer identity,
name varchar(40),
description varchar,
url varchar,
UNIQUE (name)
);

\p Creating table pctasklist
CREATE TABLE pctasklist (
id integer identity,
host varchar(20) not null,
tasksequence int not null,
pctask integer,
assigndate timestamp default current_timestamp,
completedate timestamp,
show bit default true,
FOREIGN KEY (pctask) REFERENCES pctask,
UNIQUE (host, tasksequence)
);

\p Granting privileges
GRANT select ON pctask TO public;
GRANT all ON pctask TO tomcat;
GRANT select ON pctasklist TO public;
GRANT all ON pctasklist TO tomcat;

\p Inserting test records
INSERT INTO pctask (name, description, url) VALUES (
'task one', 'Description for task 1', 'http://cnn.com');
INSERT INTO pctasklist (host, tasksequence, pctask) VALUES (
'admc-masq', 101, SELECT id FROM pctask WHERE name = 'task one');

commit;

說明:
 以/* …… */包圍的內容爲註解部分
 \c true意思爲,即使有錯誤,也是繼續執行。因此,對於”DROP TABLE pctasklist”,即使pctasklist表不存在,無法刪除該表而出錯,也會繼續執行下面的SQL語句。
 \c false則相反,意思爲,對於下面的SQL語句,出果出錯,馬上終止執行。
 \p爲打印信息,此信息在將SQL語句輸出到其他文件中時,將按原文輸出。
 當執行到GRANT all ON pctask TO tomcat;時,由於tomcat的schema(用戶或用戶組)不存在,出錯,後面的語句將不再執行,包括最後一行commit語句。
 默認情況下,SQL文本中的SQL語句在執行完畢後不會自動提交,因此需要在最後用commit;提交事務。但由於之前的SQL語句已經出錯,因此這條語句在這裏形同虛設,事務將回滾。



6. HsqlDb的關閉
根據5.1,在HsqlDb8.0中,可通過發送shutdown的SQL語句來關閉數據庫服務器:

java -jar ./lib/hsqldb.jar --sql "shutdown" localhost-sa


7. 輸出結果

輸出日誌。我們使用上面的語句來輸出報表:

java -jar ./lib/hsqldb.jar localhost-sa sample.sql > log.txt

使用”>”符號,將結果輸出至當前路徑的log.txt。執行終止後,log.txt的內容如下:

Continue-on-error is set to: true /* 對應於\c true */
Continue-on-error is set to: false /* 對應於\c false */
Creating table pctask /* 對應於\p */
Creating table pctasklist /* 對應於\p */
Granting privileges /* 對應於\p */

通過\o指令輸出SQL查詢結果。
在HsqlDb\src\org\hsqldb\sample文件夾下有一sampledata.sql文件,裏面存放了許多生成數據庫及插入數據的語句。我們先通過它來插入記錄。執行以下語句:

java -jar ./lib/hsqldb.jar localhost-sa ./src/org/hsqldb/sample/sampledata.sql

然後,在F:\temp\hsqldb文件夾下面創建一個名爲querydata.sql的文件,內容如下:

\o report.txt
select * from Product;
COMMIT;

其中,在第一行的”\o report.txt”中,”\o”爲輸出查詢結果指令,將結果存放在當前路徑的report.txt中。執行下面的語句:

java -jar ./lib/hsqldb.jar localhost-sa querydata.sql

執行後,除了在屏幕輸出我們想要的結果外,HsqlDb還在當前路徑下生成一個report.txt文件,裏面除了在屏幕上顯示的結果外,還在第一行中自動加上時間及生成工具:

# Sat Apr 29 02:26:31 CST 2006. Query output from org.hsqldb.util.SqlFile.
ID NAME PRICE
-- ----------------- -----
0 Iron Iron 5.4
1 Chair Shoe 24.8
2 Telephone Clock 24.8
……

如果以上語句再執行一遍,則會將查詢結果添加到report.txt的末端,而原來的查詢結果依然保留。

除了文本文件,我們還可以輸出html格式的網頁報表。將querydata.sql內容修改如下:

\H
\o report.html
select * from Product;
COMMIT;

“\H”指令將生成html格式的報表,而”\o”指令後面的report也相應地改成了.html文件。再次執行上面的SQL語句:

java -jar ./lib/hsqldb.jar localhost-sa querydata.sql

屏幕輸出了report.html的源碼,同時也生成了report.html文件。在querydata.sql文件中,我們打開了”\H”的指令,如果想把它改爲默認的文本格式,再設一次”\H”就行了。

Html文件也是自動添加的格式。

可以通過”\p”指令添加表頭、、”\d”指令過濾字段等。

8. Ant持續化構建
有了上面的基礎,我們可以換成ant指令,以便實現持續化構建。在F:\temp\hsqldb下新建一個build.xml文件,內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project name="appfuse" basedir="." default="help">

<property name="hsqldb.path" value="lib/hsqldb.jar" />
<property name="database.dir" value="db" />
<property name="database.name" value="testdb" />
<property name="database.urlid" value="localhost-sa" />
<property name="datafile.dir" value="src/org/hsqldb/sample/sampledata.sql" />
<property name="queryfile.name" value="querydata.sql" />
<property name="reportoutput.dir" value="report" />
<property name="reportfile.name" value="genreport.sql" />

<target name="help"
description="Show help information">
<echo level="info">HsqlDB Utils</echo>
<echo level="info">================================================================</echo>
<echo level="info">=> browseServer: Query HsqlDb with its DatabaseManagerSwing ==</echo>
<echo level="info">=> clean: Clean all output results ==</echo>
<echo level="info">=> help: Show this information ==</echo>
<echo level="info">=> shutdownServer: Shutdown HsqlDb Server ==</echo>
<echo level="info">=> startServer: Start HsqlDb Server in Server mode ==</echo>
<echo level="info">=> populate: Insert sample data ==</echo>
<echo level="info">=> queryData: Query data from database ==</echo>
<echo level="info">=> report: Make data report ==</echo>
<echo level="info">================================================================</echo>
</target>

<target name="startServer"
description="Start HsqlDb Server">
<echo level="info">Starting HsqlDb Server...</echo>
<java
classname="org.hsqldb.Server"
classpath="${hsqldb.path}"
fork="true"
failοnerrοr="true">
<arg value="-database.0" />
<arg value="file:${database.dir}/${database.name}" />
<arg value="-dbname.0" />
<arg value="${database.name}" />
</java>
</target>

<target name="shutdownServer">
<echo level="info">Shutdown HsqlDb Server...</echo>
<java
jar="${hsqldb.path}"
classpath="${hsqldb.path}"
fork="true"
failοnerrοr="true">
<arg value="--sql" />
<arg value="shutdown" />
<arg value="localhost-sa" />
</java>
</target>

<target name="browseServer"
description="Browse Database Server">
<echo level="info">Opening HsqlDb ManagerSwing...</echo>
<java
classname="org.hsqldb.util.DatabaseManagerSwing"
classpath="${hsqldb.path}"
fork="true"
failοnerrοr="true">
<arg value="-url"/>
<arg value="jdbc:hsqldb:hsql://localhost/${database.name}" />
</java>
</target>

<target name="populate"
description="Insert sample data">
<java
jar="${hsqldb.path}"
classpath="${hsqldb.path}"
fork="true"
failοnerrοr="true">
<arg value="${database.urlid}" />
<arg value="${datafile.dir}" />
</java>
</target>

<target name="queryData"
description="Query data from database">
<java
jar="${hsqldb.path}"
classpath="${hsqldb.path}"
fork="true"
failοnerrοr="true">
<arg value="${database.urlid}" />
<arg value="${queryfile.name}" />
</java>
</target>

<target name="report"
description="Make data report">
<mkdir dir="${reportoutput.dir}" />
<java
jar="${hsqldb.path}"
classpath="${hsqldb.path}"
fork="true"
failοnerrοr="true">
<arg value="${database.urlid}" />
<arg value="${reportfile.name}" />
</java>
</target>

<target name="clean"
description="Clean all outputs results">
<delete dir="${reportoutput.dir}" />
</target>
</project>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章