【摘要】
集算器提供了 JDBC 驅動,很容易嵌入到 Java 程式調用,方法和在 Java 中執行 SQL 和存儲過程類似。
結構圖如下:

1. 加載驅動 jar
集算器 JDBC 類似一個不帶實體表的資料庫 JDBC 驅動,可以把它簡單的看成是一個隻有存儲過程的資料庫。另外,集算器 JDBC 是個完全嵌入式計算引擎,已經在 JDBC 中完成了所有運算,不象資料庫那樣 JDBC 隻是個接口,實際運算在獨立的資料庫伺服器完成。
如果在 web 應用項目下,可以把這些 jar 包放在 WEB-INF/lib 目錄下。集算器 JDBC 需要三個基礎 jar 包,都可以在 [安裝目錄]\esProc\lib 目錄下找到:
dm.jar //集算器計算引擎及JDBC驅動包
icu4j_3_4_5.jar //處理國際化
jdom.jar //解析配置檔案dm.jar //集算器計算引擎及JDBC驅動包icu4j_3_4_5.jar //處理國際化 jdom.jar //解析配置檔案
除了以上的必需 jar,還有一些為完成特定功能的 jar 包:
比如資料庫作為資料源,那麼還需要相應資料庫的驅動 jar 包;
要讀寫 Office 檔案,則需要加入 poi*.jar 和 xmlbeans.jar;
要使用繪制圖形功能,則需要加入 SVG 圖形處理相關的 jar 包,包括 batik*.jar、js.jar、pdf-transcoder.jar、xalan-2.6.0.jar、xercesImpl.jar、xml-apis.jar、xml-apis-ext.jar。
2. 部署 raqsoftConfig.xml
集算器還有個重要的配置檔案 raqsoftConfig.xml,可以在 [安裝目錄]\esProc\config 下找到,需複制後放置在應用項目的類路徑下,配置檔案的名稱不可改變。
在 raqsoftConfig.xml 檔案中,配置了授權資訊、集算器主路徑、dfx 檔案尋址路徑等各類資訊。我們先看下最基本的配置,即集算器授權檔案配置:
<?xml version="1.0" encoding=" UTF-8"?>
< Config Version="2">
<Runtime>
<Esproc>
<!--集算器授權檔案配置,可以是絕對路徑,也可以是相對路徑,使用相對路徑時是相對于類路徑-->
<license>esproc.xml</license>
<!--試用授權檔案可從潤乾公司官網中下載下傳-->
</Esproc>
</Runtime>
</Config><?xml version="1.0" encoding=" UTF-8"?>< Config Version="2">
<Runtime>
<Esproc>
<!--集算器授權檔案配置,可以是絕對路徑,也可以是相對路徑,使用相對路徑時是相對于類路徑-->
<license>esproc.xml</license>
<!--試用授權檔案可從潤乾公司官網中下載下傳-->
</Esproc>
</Runtime></Config>
Java 調用
Java 程式中調用 SPL 腳本 ,與 java 中調用 SQL 和存儲過程類似,下面來看下具體是怎樣實作的:
執行 SPL 語句
比如建立一個資料表,并添加兩個字段 baseNum、square2,分别将 100 以内的自然數及其的平方值組成 100 條記錄插入到資料表中,最後将表中的資料作為結果集傳回。
Java 代碼如下:
public void runSPL() throws ClassNotFoundException, SQLException{
Connection con = null;
PreparedStatement st;
ResultSet set ;
//建立連接配接
Class._forName_("com.esproc.jdbc.InternalDriver");
con= DriverManager._getConnection_("jdbc:esproc:local://");
//直接執行SPL語句,傳回結果集
st = (PreparedStatement)con.createStatement();
ResultSet rs = st.executeQuery("=100.new(~:baseNum,~*~:square2)");
//簡單處理結果集,将結果集中的字段名與資料輸出
ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();
for ( int c = 1; c <= colCount;c++) {
String title = rsmd.getColumnName(c);
if( c > 1 ) {
System._out_.print("\t");
}
else {
System._out_.print("\n");
}
System._out_.print(title);
}
while (rs.next()) {
for(int c = 1; c<= colCount; c++) {
if ( c > 1 ) {
System._out_.print("\t");
}
else {
System._out_.print("\n");
}
Object o = rs.getObject(c);
System._out_.print(o_.toString());
}
}
//關閉連接配接
if (con!=null) {
con.close();
} public void runSPL() throws ClassNotFoundException, SQLException{
Connection con = null;
PreparedStatement st;
ResultSet set ; //建立連接配接
Class._forName_("com.esproc.jdbc.InternalDriver");
con= DriverManager._getConnection_("jdbc:esproc:local://"); //直接執行SPL語句,傳回結果集
st = (PreparedStatement)con.createStatement();
ResultSet rs = st.executeQuery("=100.new(~:baseNum,~*~:square2)"); //簡單處理結果集,将結果集中的字段名與資料輸出
ResultSetMetaData rsmd = rs.getMetaData(); int colCount = rsmd.getColumnCount(); for ( int c = 1; c <= colCount;c++) {
String title = rsmd.getColumnName(c); if( c > 1 ) {
System._out_.print("\t");
} else {
System._out_.print("\n");
}
System._out_.print(title);
} while (rs.next()) { for(int c = 1; c<= colCount; c++) { if ( c > 1 ) {
System._out_.print("\t");
} else {
System._out_.print("\n");
}
Object o = rs.getObject(c);
System._out_.print(o_.toString());
}
} //關閉連接配接
if (con!=null) {
con.close();
}
執行結果:
在 SPL 中通路本地檔案
通過 SPL 還可以通路本地的檔案,其中包括 Txt、Excel、Json、Csv、Ctx 等多種類型的檔案,通路時可以通過絕對路徑查檔案位置,也可以通過相對路徑查找,使用相對路徑時,則是相對于配置檔案中的主目錄,是以,首先我們來配置下主目錄:
在 raqsoftConfig.xml 檔案的節點 < Esproc ></ Esproc > 中添加以下節點:
<!--集算器主路徑,該路徑為單一的絕對路徑-->
<mainPath>D:\mainFile</mainPath> <!--集算器主路徑,該路徑為單一的絕對路徑-->
<mainPath>D:\mainFile</mainPath>
我們把要調用的檔案 employee.txt 放到主目錄下面,在 JAVA 中調用時,建立連接配接、輸出結果等部分的代碼與上例是完全相同的,調用 SPL 語句部分如下:
ResultSet rs=st.executeQuery("=file(\"D:\mainFile\employee.txt\").import@t()");ResultSet rs=st.executeQuery("=file(\"D:\mainFile\employee.txt\").import@t()");
這裡支援絕對路徑與相對路徑的使用,在 Java 中使用反斜杠 \ 表示轉義符。
對于這種簡單運算,還可以使用簡單 SQL 文法:
ResultSet rs=st.executeQuery("$()select * from employee.txt");ResultSet rs=st.executeQuery("$()select * from employee.txt");
其中 $() 表示通路本地檔案系統,兩種寫法的結果集相同。
帶參數的 SPL 語句
參數是 SQL 語句的一個重要組成部分,同樣,SPL 語句中也支援參數的使用,例如,像上例中,要查詢 employee.txt 檔案中的資料,但是要求隻查詢工資在 12000 到 20000 之間的記錄,并根據工資升序排序:
調用部分代碼如下:
PreparedStatement pst = con.prepareStatement("$()select * from employee.txt where SALARY > ? and SALARY< ? order by SALARY");
//設定參數
pst.setObject(1,12000);
pst.setObject(2,20000);
ResultSet rs = pst.executeQuery(); PreparedStatement pst = con.prepareStatement("$()select * from employee.txt where SALARY > ? and SALARY< ? order by SALARY"); //設定參數
pst.setObject(1,12000);
pst.setObject(2,20000);
ResultSet rs = pst.executeQuery();
其中用?表示參數,然後通過 setObject() 為上面的參數一一指派。
有資料源的 SPL 語句
集算器 JDBC 既然是個資料計算引擎,那麼資料來源的重要途徑之一就是資料庫了,JAVA 中如何來調用帶資料源的 SPL 語句呢?往下看:
JAVA 調用帶資料源的 SPL 語句之前,需要先在應用項目中添加對應的資料庫驅動,然後在配置檔案 raqsoftConfig.xml 中配置資料源資訊。
例如:調用的 SPL 語句中使用的資料源名稱為 demo,資料庫類型為 HSQL,那麼配置如下:
首先,将 HSQL 的資料集驅動 hsqldb.jar 加載到應用項目中;
其次,在 raqsoftConfig.Xml 的 < Runtime ></ Runtime > 節點中配置資料源資訊:
<DBList>
<DB name="demo"> <!--資料源名稱-->
<property name="url" value="jdbc:hsqldb:hsql://127.0.0.1/demo" ></property> <!-- url連接配接-->
<property name="driver" value="org.hsqldb.jdbcDriver" ></property> <!--資料庫驅動-->
<property name="type" value="13" ></property> <!--資料庫類型-->
<property name="user" value="sa" ></property> <!--使用者名-->
<property name="password" value=""></property> <!--密碼-->
<property name="batchSize" value="1000" ></property>
<property name="autoConnect" value="true" ></property><!--是否自動連接配接,如果設定為true,則可以直接以$開頭的SQL語句來通路資料庫,如果為false,則不會自動連接配接,使用前必須用connect(db)語句建立資料庫連接配接-->
<property name="useSchema" value="false" ></property>
<property name="addTilde" value="false" ></property>
<property name="dbCharset" value="UTF-8" ></property>
<property name="clientCharset" value="UTF-8" ></property>
<property name="needTransContent" value="false" ></property>
<property name="needTransSentence" value="false" ></property>
<property name="caseSentence" value="false" ></property>
</DB>
</DBList><DBList><DB name="demo"> <!--資料源名稱--><property name="url" value="jdbc:hsqldb:hsql://127.0.0.1/demo" /> <!-- url連接配接--><property name="driver" value="org.hsqldb.jdbcDriver" /> <!--資料庫驅動--><property name="type" value="13" /> <!--資料庫類型--><property name="user" value="sa" /> <!--使用者名--><property name="password" value=""/> <!--密碼--><property name="batchSize" value="1000" /><property name="autoConnect" value="true" /><!--是否自動連接配接,如果設定為true,則可以直接以$開頭的SQL語句來通路資料庫,如果為false,則不會自動連接配接,使用前必須用connect(db)語句建立資料庫連接配接--><property name="useSchema" value="false" /><property name="addTilde" value="false" /><property name="dbCharset" value="UTF-8" /><property name="clientCharset" value="UTF-8" /><property name="needTransContent" value="false" /><property name="needTransSentence" value="false" /><property name="caseSentence" value="false" /></DB></DBList>
現在我們通過 SPL 從 demo 資料源中查詢 SALES 表,過濾出 SELLERID 為 3 的員工,在 2014 年 11 月 11 号到 2014 年 12 月 12 号期間的所有訂單資訊:
PreparedStatement pst = con.prepareStatement("$(demo)select * from SALES where SELLERID = ? and ORDERDATE>? and ORDERDATE<?");
//設定參數
pst.setObject(1,"3");
pst.setObject(2,java.sql.Date.valueOf("2014-11-11"));
pst.setObject(3,java.sql.Date.valueOf("2014-12-12"));
//擷取結果集
ResultSet rs = pst.executeQuery(); PreparedStatement pst = con.prepareStatement("$(demo)select * from SALES where SELLERID = ? and ORDERDATE>? and ORDERDATE<?"); //設定參數
pst.setObject(1,"3");
pst.setObject(2,java.sql.Date.valueOf("2014-11-11"));
pst.setObject(3,java.sql.Date.valueOf("2014-12-12")); //擷取結果集
ResultSet rs = pst.executeQuery();
結果集輸出如下:
執行 SPL 腳本
JAVA 內建集算器 JDBC 後,除了可以直接執行單句的 SPL 語句,還可以調用更複雜的 SPL 腳本(字尾為 dfx 的檔案)。
比如下面的 dfx 檔案:
A | B | C |
1 | =demo.query("select NAME as CITY, STATEID as STATE from CITIES") | [] |
2 | for A1 | =demo.query("select * from STATES where STATEID=?",A2.STATE) |
3 | if left(B2.ABBR,1)==arg1 | >A2.STATE=B2.NAME |
4 | >B1=B1|A2 | |
5 | return B1 |
SPL 腳本思路:
循環周遊 CITIES 表記錄,通過 CITIES. STATES 過濾 STATES 表,若 STATES. ABBR 首字母為參數 arg1,則将 STATES 表中的 NAME 值賦給 CITIES. STATE,并将 CITIES 表中的這條記錄拼接到 B1 格中,最終傳回 B1 格的結果集。
在這個網格檔案中,需要從資料源 demo 中擷取資料,同時使用了參數 arg1:
資料源配置方法可以參考上面的示例,網格檔案儲存為 city.dfx,dfx 檔案可以存放在應用項目類路徑或 raqsoftConfig.xml 中配置的主目錄下,當 dfx 檔案比較多的時候,為了便于統一維護和管理,我們還可以将 dfx 檔案放到 dfx 尋址路徑中,尋址路徑的配置方式如下:
在 raqsoftConfig.xml 檔案的 < Esproc></ Esproc> 節點中,添加以下内容:
<dfxPathList>
<!--配置dfx檔案尋址路徑,該路徑為絕對路徑,可以設定多個路徑,以“;”隔開-->
<dfxPath>D:\dfxFile</dfxPath>
</dfxPathList><dfxPathList>
<!--配置dfx檔案尋址路徑,該路徑為絕對路徑,可以設定多個路徑,以“;”隔開-->
<dfxPath>D:\dfxFile</dfxPath></dfxPathList>
//通過call調用存儲過程,其中city是dfx的檔案名,?表示參數,多個參數間用逗号間隔
st =con.prepareCall("call city(?)");
st.setObject(1, "A");
//擷取結果集
ResultSet rs = st.executeQuery(); //通過call調用存儲過程,其中city是dfx的檔案名,?表示參數,多個參數間用逗号間隔
st =con.prepareCall("call city(?)");
st.setObject(1, "A"); //擷取結果集
ResultSet rs = st.executeQuery();
通過 call 調用 dfx 檔案除了上面的寫法,還可以在調用 dfx 時直接傳參,如下:
st=con.prepareStatement("call city(\"A\")");
//擷取結果集
ResultSet rs = st.executeQuery(); st=con.prepareStatement("call city(\"A\")"); //擷取結果集
ResultSet rs = st.executeQuery();
在 Java 中調用 dfx 檔案時,也可以省略 call 直接使用 dfx (…),該用法同樣有兩種寫法,如下:
//dfx名稱與參數間以空格作為分隔,多個參數間通過逗号分隔
st =con.prepareCall("city ?");
//設定參數
st.setObject(1,"A"); //dfx名稱與參數間以空格作為分隔,多個參數間通過逗号分隔
st =con.prepareCall("city ?"); //設定參數
st.setObject(1,"A");
或:
st =con.prepareCall("city \"A\""); st =con.prepareCall("city \"A\"");
以上幾種調用方法最終擷取的結果集均相同。
上述内容就是 Java 調用 SPL 腳本的常用方式了,其他程式調用 SPL 的用法: