在使用 Jasper 報表工具製做報表時,經常會遇到數據來自多個數據源的狀況,一般的作法是使用主子報表或者使用javabean做爲數據源。使用主子報表一般會增長報表設計的複雜度,而使用javabean作數據源,則須要一個javabean類來支持,而且爲了在設計報表時可以看到數據,還要爲ireport提供一個靜態方法,該方法用於返回上面定義javabean的一個結果集。java
顯然,上面這兩種辦法都不太方便,本文將提供一種更加簡便的方法,那就是經過集算器來解決ireport中的多數據源問題,並進一步提升ireport的性能。咱們將以JasperReport5.6.0 開發環境爲例進行介紹。mysql
報表項目中,經常會出現報表源數據來自不一樣數據庫的狀況,例如同一應用系統的數據庫負載太大,不得已分紅多個數據庫,就像是最多見的銷售系統數據分紅當前庫和歷史庫,一部分數據存於數據庫一部分數據存於文件等。sql
在多數據源的數據庫類型方面,報表工具可能鏈接一樣類型的數據庫,好比都是mysql或者 oracle;也多是不一樣的類型,如txt、csv或者Excel等。數據庫
咱們的例子中,報表數據一部分來自mysql數據庫,一部分來自文本文件。緩存
其中,mysql數據庫的employee表存儲EID爲1-100000的數據,內容以下:性能優化
而data.txt文件中存儲EID爲100001-101000的數據,內容以下:oracle
咱們的任務是在ireport中製做一張報表,查看employee表和emp.txt文件合併後的全部數據。這一需求經過集算器協助 ireport能夠輕鬆實現。集算器使用咱們稱之爲結構化處理語言(Structured Process Language,簡稱SPL),具體的SPL代碼以下:ide
A | |
1 | =connect("mysql") |
2 | =A1.query@x("select * from employee") |
3 | =file("F:\\files\\emp.txt").import@t() |
4 | =[A2,A3].conj() |
5 | return A4 |
A1:建立數據源鏈接,鏈接mysql數據源。工具
A2:在mysql數據源中查詢employee表中的數據,並返回查詢結果。性能
A3:讀取文件emp.txt的內容。
A4:合併A2和A3數據。
A4:將A4合併後的結果返回給報表。
爲了在報表中呈現計算結果,咱們須要將以上 SPL 代碼存爲文件 employee.dfx,而後就能夠利用集算器對外提供的 JDBC 接口調用這個腳本了。
在報表工具中經過創建 JDBC 數據源引入集算器腳本的方法和調用存儲過程同樣,在 Jasper 的 SQL 設計器中能夠用call employee()
來調用。具體步驟在《JasperReport 調用 SPL 腳本》一文中有詳細的描述。
而後,咱們能夠在ireport 中設計一個最簡單的報表employee.jrxml,模板以下:
預覽後能夠直接看到報表結果了:
顯然,這個過程相比傳統的主子報表或者javabean方法要簡單很多,更重要的是,計算邏輯很是清晰,集成方式也幾乎沒有任何學習成本。
在解決了基本的功能需求後,咱們還能夠進一步將焦點關注到性能方面。報表項目中,經常須要將多個錶鏈接查詢,在這些被鏈接的表中,可能會包含海量的數據。例如:將僱員表和訂單表經過共有字段員工編號鏈接起來,以便查看某些訂單的銷售人員的信息。顯然,訂單表會隨着時間的推移不斷增加,最終帶來嚴重的系統負擔。
下面例子中的報表數據一部分來自mysql數據庫的employee表,一部分來自mysql數據庫的sales表。
其中,employee表存儲EID爲1-3000000的僱員數據,內容以下:
而訂單數據sales表則存儲了76萬條數據,並且持續增長。其中的數據內容樣例以下:
爲了實現鏈接查詢,咱們在ireport 中設計一個最簡單的報表mysql_join.jrxml,模板以下:
首先咱們看一下傳統作法的表現。咱們須要查詢早於2015-04-01,由EID小於1000001的僱員產生的銷售數據,SQL 語句以下:
select sales.OID,sales.Date,sales.EID,sales.Amount,employee.Name from sales join employee on sales.EID=employee.EID where sales.Date<'2015-04-01'and employee.EID<1000001select sales.OID,sales.Date,sales.EID,sales.Amount,employee.Name from sales join employee on sales.EID=employee.EID where sales.Date<'2015-04-01'and employee.EID<1000001
點擊預覽,在咱們的測試環境下,101s後展示計算結果:
接下來,咱們看看用集算器jdbc的運行效果。將上邊的報表另存爲esproc_join.jrxml。
而後編寫以下的SPL代碼:
A | |
1 | =connect("mysql") |
2 | =A1.cursor("select * from sales where Date<'2015-04-01'") |
3 | =A1.query("select EID,Name from employee where EID<1000001").keys(EID) |
4 | =A2.join@i(EID,A3:EID,Name) |
5 | return A4.fetch() |
A1:建立數據源鏈接,鏈接mysql數據源。
A2:查詢sales表中Date早於2015-04-01的數據,將結果返回成遊標。
A3:查詢employee表中EID小於1000001的EID列和Name列的數據。
A4:遊標A2與序表A3外鍵式鏈接。
A5:將遊標的結果返回給報表。
接下來和前一個例子同樣,將以上 SPL 代碼存爲文件esproc_join.dfx,並在數據源中定義SQL:
call esproc_join()call esproc_join()
如今,咱們點擊預覽,在一樣的測試環境下,14s後就獲得了徹底相同的計算結果。
可見,使用集算器在簡化了ireport訪問多數據源的同時,還能夠大大提升ireport的性能。本文中的例子只是集算器中一些簡單的應用。事實上,基於集算器的靈活性,使用集算器提升性能的辦法有不少,包括並行取數、可控緩存、控制SQL執行路徑、減小隱藏格、引入數據計算層等等。更多更高級的使用快來乾學院看看吧!