在開發程序過程中,自從無意中使用了HsqlDb後,由於其速度特快,愛不釋手(“不用不知道,誰用誰知道”),將原來所使用的Sybase,Sql Anywhere, MySQL全都通通扔到了一邊。在持續化構建過程中,因其尚未提供ant的第三方任務插件,因此需要清楚地了解在命令行下進行相應操作的方法,再通過<Java>進行轉化,進而針對其特點特作此小結。而大眾化的知識,如驅動類名(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
服務器模式:允許多個連接
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
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語句已經出錯,因此這條語句在這裡形同虛設,事務將回滾。
根據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
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="appfuse" />
<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"
failonerror="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"
failonerror="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"
failonerror="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"
failonerror="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"
failonerror="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"
failonerror="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>