JDBC控件是Beehive1.0中提供的訪問JDBC數據源的java控件。通過繼承JDBC控件,我們根本無須關注訪問數據庫資源的通訊細節,只需要定義自己的業務方法,增加相應的注釋來描述該繼承子類,我們就可以非常輕松的實現企業應用中JDBC數據源的訪問。
JDBC控件的所有注釋在org.apache.beehive.controls.system.jdbc.JdbcControl接口中定義,Beehive編譯器在編譯時將檢查這些注釋是否使用正確。
本節中首先將通過一個簡單的例子來演示如何通過繼承JDBC控件來訪問JDBC數據源,完成一個數據表的增加、刪除、修改、查詢等業務邏輯,隨后將介紹如何使用JDBC控件訪問JDBC數據源的更多技巧。
本文中所有例子的源代碼可以通過下載資源區的鏈接下載。
本節中所有演示例子對應的JDBC數據源均為MySQL數據庫。
第一個JDBC控件的例子
接下來的這段例子將演示如何通過繼承JDBC控件來完成JDBC數據源的訪問,實現JDBC數據源中一個數據表中記錄增加、刪除、修改和查詢的業務邏輯。
在演示例子中,為了保證演示的簡潔,我們使用JDBC直接連接到數據庫,而沒有使用通常訪問數據庫所采用的DataSource技術。
建立數據表
在本地MySQL數據庫的Demo數據庫實例中按照如下DDL建立相應的數據表。
create table demo(
id int(5) PRimary key auto_increment,
name varchar(20) not null default '',
value varchar(20) not null default ''
);
建立表征Demo對象的JavaBean
創建新的應用目錄,然后創建表征Demo對象的JavaBean
清單1 src/org/vivianj/beehive/controls/examples/controls/beans/
Demo.java
1. package org.vivianj.beehive.controls.examples.beans;
2.
3.
4. /**
5. * Demo 用于表征Beehive JDBC控件例子中的Demo對象
6. */
7. public class Demo implements java.io.Serializable{
8. private int id;
9.
10. private String name;
11.
12. private String value;
13.
14. public int getId() {
15. return id;
16. }
17.
18. public void setId(int id) {
19. this.id = id;
20. }
21.
22. public String getName() {
23. return name;
24. }
25.
26. public void setName(String name) {
27. this.name = name;
28. }
29.
30. public String getValue() {
31. return value;
32. }
33.
34. public void setValue(String value) {
35. this.value = value;
36. }
37.
38. }
繼承JDBC控件,增加自己的業務方法
清單2 src/org/vivianj/beehive/controls/examples/controls/
DemoMySQLControl.java
1. package org.vivianj.beehive.controls.examples.controls;
2.
3. import org.apache.beehive.controls.api.bean.ControlExtension;
4. import org.apache.beehive.controls.system.jdbc.JdbcControl;
5. import org.vivianj.beehive.controls.examples.beans.Demo;
6.
7. /**
8. * DemoMySQLControl 用于封裝訪問MySQL數據庫中的Demo數據
9. 表的所有業務邏輯
10. * 包括新增、刪除、修改、根據id查找對應的記錄、查找所有Demo
11. 數據表中的記錄、根據條件查找所有數據表中的記錄
12. * 數據庫訪問時根據參數從DriverManager中獲取數據庫連接
13. */
14.
15. @ControlExtension
16. @JdbcControl.ConnectionDriver(
17. databaseDriverClass = "org.gjt.mm.mysql.Driver",
18. databaseURL = "jdbc:mysql://localhost/estore ",
19. userName = “root”, passWord = “root”)
20. public interface DemoMySQLControl extends JdbcControl {
21. /**
22. * 向數據表demo中增加新的記錄
23. *
24. * @param demo
25. * 新增加的Demo對象
26. */
27. @SQL(statement = "insert into demo(name,value)
28. values({demo.name},{demo.value})")
29. public void createDemo(Demo demo);
30.
31. /**
32. * 修改數據表demo中demo.id對應記錄的name和value信息
33. *
34. * @param demo
35. * 被修改的Demo對象
36. */
37. @SQL(statement = "update demo set name={demo.name},
38. value={demo.value} where id={demo.id}")
39. public void updateDemo(Demo demo);
40.
41. /**
42. * 刪除數據表demo中demoId對應的記錄
43. *
44. * @param demoId
45. * 被刪除的Demo對象的id屬性
46. */
47. @SQL(statement = "delete from demo where id={demoId}")
48. public void deleteDemo(int demoId);
49.
50. /**
51. * 根據demoId查找Demo數據庫中對應的記錄,返回對應的
52. Demo對象
53. *
54. * @param demoId
55. * 查找Demo對象的id屬性
56. * @return id屬性為demoId的記錄
57. */
58. @SQL(statement = "select id,name,value from demo
59. where id={demoId}")
60. public Demo getDemoById(int demoId);
61.
62. /**
63. * 返回Demo數據表中所有記錄集合
64. *
65. * @return Demo數據表中所有記錄集合
66. */
67. @SQL(statement = "select id,name,value from demo")
68. public Demo[] getDemos();
69.
70. /**
71. *
72. * @param name
73. * @return
74. */
75. @SQL(statement = "select id,name,value from demo
76. where name like {sql: name}")
77. public Demo[] getDemosFilterByName(String name);
78. }
控件調用
我們可以編寫DemoMySQLControl控件的測試類,然后通過如下方式來完成控件中業務方法的調用。
在測試類中采用聲明式控件實例化方式來實例化DemoMySQLControl控件。
DemoMySQLControl _control;
調用控件的相關業務方法來實現業務邏輯。
下面的代碼段可以完成Demo對象的新增功能。
Demo demo = new Demo();
demo.setName(“name”);
demo.setValue(“value”);
_control.createDemo(demo);
實例分析
從上面的例子中我們可以看到,通過繼承JDBC控件來完成JDBC數據源的訪問是一件非常簡單的事情,開發者需要完成的工作被簡化為兩項:編寫表征訪問對象的JavaBean和使用聲明完成業務方法和邏輯的實現,這樣的開發過程大大的簡化了開發者的工作,極大地減少了開發者的代碼編寫量。
下面我們詳細的分析一下繼承JDBC控件的子類DemoMySQLControl:
15. @ControlExtension
在程序的第15行,我們使用@ControlExtension來注釋將要創建的這個接口繼承了另外的控件接口
16.@JdbcControl.ConnectionDriver(
17.databaseDriverClass = “org.gjt.mm.mysql.Driver”,
18.databaseURL = "jdbc:mysql://localhost/estore ",
19.userName = “root”, password = “king”)
在程序的第16~19行我們使用@JdbcControl.ConnectionDriver注釋來為將要創建的接口指定一些需要傳遞的參數,這里主要是一些數據庫訪問時所需要的JDBC驅動類、JDBC訪問URL、數據庫訪問用戶名和密碼等必要信息。
20.public interface DemoMySQLControl extends JdbcControl { 在程序的第20行使用extends關鍵字表示將要創建的接口DemoMySQLControl和JdbcControl接口之間的繼承關系
27.@SQL(statement = "insert into demo(name,value)
28.values({demo.name},{demo.value})")
在程序的第27~28行使用@SQL關鍵字注釋接下來定義的這個業務方法所需要執行的業務邏輯,其中的{}表示對傳入參數的調用,{}包含的內容表示了需要處理的參數,這些參數的表示方法遵循面向對象的屬性調用方式,JDBC控件的解析器會將這些代碼轉化為對應的getter方法調用。
29.public void createDemo(Demo demo);
在程序的第29行,采用常用的接口方法聲明了該控件的一個訪問接口。
后面的代碼采用和27~29行相應的原理定義了其它需要實現的業務方法。需要注意的是,定義查詢類方法時,如果只需要返回一條記錄,目前通常的做法是返回一個Demo對象。如果返回的記錄有超過一條的可能性,返回的是符合查詢條件的Demo對象數組、List對象等,請參考《JDBC控件返回類型》部分的內容。
前面的內容中,我們已經通過繼承JDBC控件完成了訪問數據庫資源的全部內容,現在你可以編寫單元測試代碼來測試控件是否符合要求了。請大家參考《控件入門》中的步驟完成JDBC控件的編譯和單元測試工作。
到現在為止,我們已經知道了如何使用JDBC控件和注釋來訪問數據庫資源的基本步驟和方法,但是還沒有學習如何使用注釋來讓JDBC控件和業務內容的結合起來。這部分的內容分作兩部分進行介紹:一是如何通過注釋定制JDBC控件,提供訪問數據庫的信息(比如數據庫訪問方式、URL、用戶名和密碼等),一是如何確定每次業務方法執行的返回對象。
使用注釋訂制JDBC控件
本節中的內容將給大家介紹如何使用JDBC控件提供的注釋根據不同的環境和要求來訂制JDBC控件,完成JDBC數據源的訪問和業務邏輯的封裝。
JDBC控件支持的四個注釋:ConnectionDataSource、ConnectionDriver、ConnectionOptions、SQL。四個注釋中ConnectionDataSource、ConnectionDriver、ConnectionOptions是用于類級別的注釋,用于描述JDBC控件繼承類,SQL注釋是方法級別的注釋,用于描述JDBC繼承類中的業務方法。
使用ConnectionDataSource注釋可以指定JDBC控件訪問數據庫時根據采用DataSource方式獲取數據庫連接。使用ConnectionDriver注釋可以指定JDBC控件訪問數據庫時使用指定的參數通過DriverManager獲取數據庫連接。ConnectionOptions注釋描述了數據庫訪問時的一些擴展特性,比如數據庫訪問時是否使用READONLY優化(仍然可以進行UPDATE操作)等。
下面開始詳細的介紹這些注釋,并且通過提供簡單的代碼段來說明如何使用這些注釋來配置JDBC控件的繼承類。
ConnectionDriver注釋
ConnectionDriver用于注釋JDBC控件的繼承類,控制JDBC控件在訪問數據庫的時候通過DriverManager獲取數據庫連接。ConnectionDriver注釋支持5個參數:databaseDriverClass、databaseURL、userName、password、properties。
·databaseDriverClass
String類型,用于設定數據庫驅動類的全名。使用ConnectionDriver注釋時必須設置的參數。
比如訪問MySQL數據庫,可以使用databaseDriverClass= “org.gjt.mm.mysql.Driver”,訪問Oracle數據庫的時候可以使用databaseDriverClass= “oracle.jdbc.driver.OracleDriver”
·databaseURL
String類型,用于設定數據庫訪問的JDBC URL,使用ConnectionDriver注釋時必須設置的參數。
比如訪問MySQL可以使用databaseURL=“ jdbc:mysql://localhost/estore”,訪問Oracle數據庫時可以使用databaseURL=“ jdbc:oracle:thin:@localhost:1521:www”
·userName
String類型,設置訪問數據庫時使用的用戶名,可選參數。
·password
String類型,設置訪問數據庫時使用的密碼,可選參數。
·properties
String類型,設置訪問數據庫時的一些其它參數,可以一次性傳遞多個參數,兩個參數之間用逗號隔開。
在《第一個JDBC控件的例子》中,我們提供的代碼已經演示了如何使用ConnectionDriver注釋JDBC控件,請參見 清單2 。
ConnectionDriver注釋的JDBC控件運行時,必須保證databaseDriverClass中指定的數據庫驅動類位于classpath中,否則控件運行時將拋出違例。
ConnectionDataSource注釋
ConnectionDataSource注釋用于指定JDBC控件在訪問數據庫時通過DataSource獲取數據庫連接,它有兩個屬性:jndiName和jndiContextFactory。
·jndiName
String類型,用于設置DataSource在目標容器內的jndiName屬性
·jndiContextFactory
Class類型,用于設置數據庫訪問時可以獲取jndi上下文環境的類,被傳入的參數類必須繼承org.apache.beehive.controls.system.jdbc.JdbcControl. JndiContextFactory類,并且覆蓋JndiContextFactory類的getContext()方法,getContext()將獲取訪問目標容器的上下文環境(Context)。
下面的章節中我們將看到如何通過JDBC控件和ConnectionDataSource注釋訪問Tomcat服務器,獲取jndiName為jndi/samplesDataSource的DataSource資源,該DataSource連接到MySQL數據庫的Demo實例,Web應用部署在Tomcat環境中。
修改Tomct配置文件,創建DataSource資源
·如何創建Tomcat環境下的DataSource資源請參考Tomcat的幫助文檔。
修改Web應用的配置文件web.xml,增加如下內容,增加對資源的引用
Datasource example
jndi/samplesDataSource
javax.sql.DataSource
Container
·創建訪問Tomcat服務器Jndi上下文的類JndiContextFactory
JndiContextFactory類繼承自JdbcControl.JndiContextFactory父類,覆蓋父類中的抽象方法----getContext(),清單3 中顯示了JndiContextFactory類定義和實現的完整代碼。
清單3 src/ org/vivianj/beehive/controls/examples/controls/
jndicontext/JndiContextFactory.java
1. package org.vivianj.beehive.controls.examples.controls.jndicontext;
2.
3. import java.util.Hashtable;
4.
5. import javax.naming.Context;
6. import javax.naming.InitialContext;
7.
8. import org.apache.beehive.controls.system.jdbc.JdbcControl;
9.
10. /**
11. * JndiContextFactory 用于從Tomcat服務器中獲取訪問JNDI內容的上下文環境
12. */
13. public class JndiContextFactory extends JdbcControl.JndiContextFactory {
14. /**
15. * 獲得本地Tomcat服務器中訪問JNDI內容的上下文環境
16. *
17. */
18. public Context getContext() {
19.
20. Context ctx = null;
21.
22. try {
23. ctx = (Context)(new InitialContext().lookup("java:/comp/env"));
24. } catch (Exception e) {
25.
26. }
27.
28. return ctx;
29. }
30. }
我們可以使用ConnectionDataSource注釋和新創建的JndiContextFactory類來注釋JDBC控件了。
下面的代碼片斷就是一個簡單的例子,使用這段代碼注釋的JDBC控件,調用任何業務方法時,將通過本地Tomcat服務器上、JNDI名為“jndi/ samplesDataSource”的DataSource資源獲取數據庫連接。
@JdbcControl.ConnectionDataSource(
jndiName = "jndi/samplesDataSource",
jndiContextFactory=JndiContextFactory.class)
ConnectionOptions注釋
ConnectionOptions可以用于定義訪問數據庫時的一些擴展特性,可以選擇性的和ConnectionDataSource或者ConnectionDriver一起使用。ConnectionOptions支持三個參數:readOnly、resultSetHoldability、typeMappers。
·readOnly
boolean類型,如果設置為true,數據庫連接將優化為ReadOnly的訪問方式,但是仍然可以進行更新和刪除操作。默認為false。
·resultSetHoldability
org.apache.beehive.controls.system.jdbc.JdbcControl.HoldabilityType類型,可以選擇為HOLD_CURSORS_OVER_COMMIT或者CLOSE_CURSORS_AT_COMMIT,用于設置ResultSet指針的關閉策略,默認值是CLOSE_CURSORS_AT_COMMIT,表示在每次commit之后關閉ResulSet對象指針。
·typeMappers
org.apache.beehive.controls.system.jdbc.JdbcControl.TypeMapper數組類型。設置SQL自定義類型和Java類型之間的映射。TypeMappers類中指定的Java類型必須實現java.sql.SQLData接口
SQL注釋
SQL注釋用于描述JDBC控件繼承類中定義的方法,主要設置被注釋方法調用時需要執行的SQL語句和其它功能。我們可以回頭看一看清單2,里面的每一個業務方法之前均有@SQL注釋。
SQL注釋支持很多屬性設置,包括statement、arrayMaxLength等,其中最重要的就是statemet,本節中我們討論statement屬性的設置,其他屬性的設置方法請大家參考Beehive的幫助文檔,在大多數的情況下最好不要設置這些屬性,因為里面可能用到JDBC3.0規范中的新特性,而現在很多數據庫驅動并不支持這些特性。
statement內容描述了我們需要完成的業務邏輯,在statement中我們可以使用變量的方式訪問被注釋方法中傳遞進來的參數,JDBC控件的解析器在運行時保證這些參數的正確傳遞。
statement編寫規則
SQL注釋的statement屬性提供了被注釋方法調用時執行的SQL語句的內容,SQL語言中可以使用JdbcControl提供的特殊語法直接訪問Java對象或者它的屬性。編寫statement必須滿足以下條件。
·statement中的sql語句編寫方式和要求參考目標數據庫的sql語句編寫方式和要求。
·statement中使用{…}聲明變量來獲取業務方法調用時所傳遞參數或者它的屬性。
·statement中變量聲明的第一個字符和最后一個字符不能是空格,也就是說不能出現{ a}或者{a }這樣的情況,否則可能執行結果和您期望的會有很大的出入
·{}中間的內容是大小寫敏感的。如果傳入的參數名為a,而{}中引用為A,他們之間將無法匹配。
·{}中間的內容可以是參數名(傳入的參數是Java基本數據類型時適用),或者是參數對象的某個成員變量(傳入的參數是Java類對象時)。
·{}中引用Java對象的字段時,必須保證該字段符合以下條件之一,否則Java控件調用時將會返回一個違例:
* 該字段被public關鍵字聲明為公共字段,可以使用 對象名.字段名 直接訪問
* 該字段被private關鍵字聲明為私有字段,但是提供了公共的getter方法,可以通過 對象名.get屬性名 方式訪問。
* 該Java對象繼承了java.util.Map接口,可以通過 對象名.get(“屬性名”)方式訪問
statement中引用業務方法中傳遞的參數時必須保證這些參數和對應的數據表的字段類型保持一致,不能出現數據表的字段是NUMBER類型,而對應的參數卻是String類型。
當業務方法傳遞的日期或者時間類型的參數需要在statement中被引用時,請保證這些傳遞的日期和時間使用的是java.sql包中的對應類,比如我們應該使用java.sql.Date而不要使用java.util.Date來傳遞日期類型的變量給statement
statement中不能出現單引號。如果確實需要使用單引號,必須采用特別的方法解決。
statement創建實例
·不從業務方法獲取參數
下面的業務方法聲明可以從demo表中取出所有所有記錄,返回一個Demo對象的數組。
@SQL(statement=“select * from demo” )
Public Demo[] getDemos();
·從業務方法中獲取基本類型參數
下面的statement中,我們使用{demoId}變量從getDemoById()方法調用中獲取傳入的參數demoId。
@SQL(statement=“select * from demo where id={demoId}” )
Public Demo[] getDemoById(int demoId);
·從業務方法中獲取Java對象類型參數
下面的statement中,我們使用{demo.name}變量表示從createDemo ()方法調用中獲取傳入的Java類對象demo的name屬性的內容。
@SQL(statement = “insert into demo(name,value)
values({demo.name},{demo.value})”)
public void createDemo(Demo demo);
·從業務方法中獲取完整SQL語句
有些時候,SQL語句可能需要動態生成,這時候statement默認的方式無法幫開發者完成這個過程,而是需要在Java代碼中完成SQL語句的組裝后傳遞給業務方法,這種情況下我們可以使用{sql: …}的方式向statement中傳遞一個完整的sql語句。
@SQL(statement=“{sql: totalsql}” )
Public Demo[] getDemos(String totalsql);
·從業務方法中獲取SQL語句片斷
statement還支持某一段SQL語句從業務方法的參數中獲取,比如下面的這個例子中,只有最后的{sql: name}來源于業務方法中的參數。
@SQL(statement = “select id,name,value from demo
where name like {sql: name}”)
public Demo[] getDemosFilterByName(String name);
這種方式可以解決SQL語句中包含引號等特殊字符的問題,解決方法是你可以在業務方法調用之前使用Java代碼創建包含這些特殊字符串的內容,然后通過sql片斷的方式發送給statement。
這種方式另外一種用途是可以解決SQL語句部分片斷需要動態生成的問題,舉個例子,我們的多條件查詢的條件下,用戶可以選擇按照一個或者多個條件進行查詢,所以where語句后面的條件是動態的,這種情況下,我們就可以把判斷和SQL語句中where語句的生成這部分功能實現分離到Java語句中,然后作為業務方法調用參數傳遞到statement中來。
調用存儲過程
JDBC控件支持對存儲過程的調用,只需要在statement中配置里面采用{call …}這樣的方式表示當前執行的是一個存儲過程就可以了,下面的例子演示了如何調用存儲過程以及如何向調用過程傳遞參數。
@SQL(statement=“call sp_updateData({keyVal}, {intVal})”
void call_sp_updateCust(short keyVal, int intVal);
控件返回類型
繼承JDBC控件后聲明業務方法時,查詢類業務方法需要返回數據,在業務邏輯中,需要返回的業務數據通常可以分為三種:
·簡單字段。
比如要查詢今天有多少人訪問了我們的系統、編號Id為1000的用戶他的真實姓名是什么?。
·單條記錄。
比如查詢結果需要返回編號為1000的用戶。
·多條記錄。
比如查詢結果需要返回所有系統用戶。
本節中將按照這三種不同的情況給大家介紹JDBC控件所支持的返回類型以及內部處理機制。
使用控件返回簡單字段
JDBC控件支持所有Java基本類型及其對應對象類型的返回,比如int、Integer、String等,在繼承JDBC控件后聲明業務方法時,只需要聲明所需要的返回類型,JDBC控件會自動將SQL操作結果造型為所需要的返回類型。
比如我們聲明一個業務方法:
@SQL(statement = “select count(*) from demo”)
public int getDemosCount();]
控件調用后的結果將返回一個int數值,而如果你聲明的業務方法如下:
@SQL(statement = “select count(*) from demo”)
public Integer getDemosCount();
控件調用后的結果將返回一個Integer對象。
返回結果為簡單字段時,如果SQL語句執行后沒有符合要求的結果,控件將根據聲明的返回類型返回不同的值,如果聲明返回結果為數值型,那么返回結果為0;如果聲明返回結果為boolean,那么將返回false,而如果聲明的返回結果為類類型,那么控件調用返回結果為null。
使用控件返回單條記錄
當SQL查詢語句需要返回單條記錄時,控件支持兩種不同的返回類型:JavaBean對象或者Map(或者HashMap)對象。如果能夠確定返回對象的屬性,通常采用返回JavaBean對象,比如要查找id為1000的系統訪問者的詳細信息,通常我們知道系統訪問者的所有細節,所以使用JavaBean對象作為訪問信息。如果無法確定返回對象的詳細屬性或者時返回對象的屬性經常發生變化,比如我們的業務方法中可能返回一個系統訪問者的信息,也可能返回的是一個管理員的信息,那么我們可以選擇使用Map(或者HashMap)對象聲明為業務方法的返回對象。
返回JavaBean對象
這種情況下,控件將在SQL語句執行結束后,自動構造一個返回結果聲明類型的對象,調用它的相關setter方法初始化這個對象,然后返回這個對象。如果初始化過程中沒有找到合適的setter方法,系統將拋出違例信息。
我們可以通過如下的聲明,控制控件在調用后返回一個Demo對象:
@SQL(statement = “select id,name,value from demo
where id={demoId}”)
public Demo getDemoById(int demoId) ;
可聲明為返回JavaBean類型的Java類必須符合以下條件:
·Java類必須提供和statement中聲明的返回字段對應的getter和setter方法。這些getter和setter方法必須支持大小寫敏感。Java類中必須包含但不僅限于這些getter和setter方法。
·Java類中每個getter和setter方法定義的數據類型必須和數據庫表中的數據類型保持一致。
如果該Java類是某個類的內部類,那么這個類必須使用public static關鍵字定義類聲明。
返回Map(或者HashMap)對象
在不確定返回對象詳細信息的情況下,我們可以聲明返回對象類型為Map(或者HashMap),這種情況下,控件在SQL調用完成以后,將調用Map(或者HashMap)的put方法,將返回結果映射為Map(或者HashMap)對象,返回Map(或者HashMap)對象對象中鍵--值對的鍵就是數據表字段名稱,鍵是大小寫敏感的,返回Map(或者HashMap)對象中的所有鍵都被變成了大寫字母,值就是數據表字段包含的值,值的類型和數據庫中對應字段的類型有關。
我們可以通過如下的聲明,控制控件在調用后返回一個Map(或者HashMap)對象:
@SQL(statement = “select id,name,value from demo where id={demoId}”)
public HashMap getDemoById(int demoId) ;
在業務方法聲明為返回單條記錄時,如果該記錄的對應字段為空,那么返回結果的對應字段將根據對應屬性的類型被初始化null、0或者false,如果SQL語句實際執行時沒有找到符合條件的記錄,控件的默認返回結果為null,如果SQL語句實際執行時返回了多條記錄,那么控件將默認將符合條件的第一條記錄作為返回結果。
使用控件返回多條記錄
SQL查詢語句的返回結果通常是一個以上的記錄,JDBC控件支持使用數組、Iterator對象、ResultSet對象和XMLBeans對象來返回可能的多條記錄。控件開發者需要根據不同的情況選擇合適的返回對象,既要考慮讓控件使用者操作簡單,也要考慮可能引起的其他問題。
使用數組返回多條記錄對控件使用者而言是最好的方式,因為數組的遍歷不需要更多的JavaAPI知識。然而數組只能在數據庫操作完成以后一次性生成,因此整個ResultSet對象將被緩存,所以如果查詢結果是一個非常大的ResultSet的時候,可能會造成系統內存耗盡的情況,這種情況下,使用數組返回多條記錄的控件開發者必須考慮數據的分批提取策略。
使用Iterator對象返回多條記錄對控件的使用者提出了更高的要求,這種情況下,Iterator對象封裝了ResulSet的數據獲取行為,控件使用者在調用Iterator對象的next方法時,容器會調用ResultSet的對應方法從數據庫中獲取對應的記錄,這種方式不存在ResultSet集大或者小的問題。當時這種方式不適合在PageFlow中使用,因為PageFlow的Action調用完成后跳轉到顯示頁面使用Iterator對象時,數據庫連接通常已經被關閉了,ResultSet已經無法獲取相應的數據了,所以Iterator對象中的數據也無法得到。
JDBC控件也支持直接返回ResulSet對象,以便控件使用者能夠自由的控制SQL語句操作結果。
如何使用數組返回多條記錄
這種情況下你可以有兩種選擇:返回JavaBean對象數組或者Map(或者HashMap)數組。這兩種情況的區別請參考章節<<如何返回單條記錄>>中的相關內容。
我們可以使用下面這段代碼聲明業務方法返回JavaBean對象數組:
@SQL(statement = “select id,name,value from demo”)
public Demo[] getDemos() ;
如果需要聲明業務方法返回的結果被封裝成Map(或者HashMap)數組,請參考使用下面的這段代碼:
@SQL(statement = “select id,name,value from demo”)
public Map[] getDemos() ;
如果SQL語句執行后沒有符合條件的記錄返回,上面的這兩種情況下將返回一個長度為0的數組。
如何使用Iterator對象返回多條記錄
和上面的情況一樣,你可以選擇Iterator中包含的對象是JavaBean對象或者是Map(或者HashMap)對象。
我們可以使用下面這段代碼聲明業務方法返回Iterator中包含的是JavaBean對象:
@SQL(statement = “select id,name,value from demo”,
iteratorElementType=Demo.class)
public java.util.Iterator getDemos() ;
如果需要聲明業務方法返回的Iterator中使用Map(或者HashMap)封裝單條記錄的所有屬性,請參考使用下面的這段代碼,其中的iteratorElementType聲明返回Iterator結果中包含的是HashMap對象:
@SQL(statement = “select id,name,value from demo”,
iteratorElementType=java.util.HashMap.class)
public java.util.Iterator getDemos() ;
后面這種情況下,返回結果中的HashMap對象的所有鍵(Key)都已經被變成了大寫,控件使用者在訪問時請注意這一點,不然可能引起程序的不正常運行。
如何使用ResultSet對象返回多條記錄
這種方式的聲明代碼如下:
@SQL(statement=“SELECT * FROM customer”)
public java.sql.ResultSet findAllCustomersResultSet();
基于大家熟知的性能方面的考慮,不推薦控件開發者使用這種方式來返回多條記錄。
結束語
數據庫資源是企業應用中的主要資源形式之一,所以如何訪問數據庫資源是企業應用中的重要內容。控件架構中的JDBC控件大大的簡化了數據庫訪問資源的復雜性、難度,開發者只需要通過簡單的繼承org.apache.beehive.controls.system.jdbc.JdbcControl,然后通過提供相應的注釋就可以完成數據庫資源的訪問和操作結果的返回。
本文中,作者首先通過簡單的例子介紹了JDBC控件使用的基本步驟,然后詳細的介紹了JDBC控件提供的主要注釋和使用方法,最后介紹了如何通過JDBC控件返回操作結果的方式方法。
新聞熱點
疑難解答