在前面的例子中,只使用了 SQL Map 最簡單的形式。SQL Map 的結構中還有其他更多 的選項。這里是一個 mapped statement 較復雜的例子,使用了更多的特性。
1 <sqlMap id=”Product”> 2 3 <cacheModel id=”productCache” type=”LRU”> 4 5 <flushInterval hours=”24”/> 6 7 <property name=”size” value=”1000” /> 8 9 </cacheModel> 10 11 <typeAlias alias=”product” type=”com.ibatis.example.Product” /> 12 13 <parameterMap id=”productParam” class=”product”> 14 15 <parameter property=”id”/> 16 17 </parameterMap> 18 19 <resultMap id=”productResult” class=”product”> 20 21 <result property=”id” column=”PRD_ID”/> 22 23 <result property=”description” column=”PRD_DESCRIPTION”/> 24 25 </resultMap> 26 27 <select id=”getProduct” parameterMap=”productParam” resultMap=”productResult” 28 29 cacheModel=”product-cache”> 30 31 select * from PRODUCT where PRD_ID = ? 32 33 </select> 34 35 </sqlMap>
雖然框架為您做了很多工作,為了完成一個簡單的查詢操作,依然需要做很多。 別擔心,下面是一個簡潔版本。
1 <sqlMap id=”Product”> 2 <select id=”getProduct” parameterClass=” com.ibatis.example.Product” 3 resultClass=”com.ibatis.example.Product”> 4 select 5 PRD_ID as id, 6 PRD_DESCRIPTION as description from PRODUCT 7 where PRD_ID = #id# 8 </select> 9 </sqlMap>
簡潔版本的行為和前一個聲明的行為不太一樣。首先,簡潔版本沒有定義緩存,因 此每一個請求都要讀取數據庫。其次,簡潔版本使用了框架的自動映射特性,這將帶來一些 副作用。但是,這兩者在 Java 代碼中的執行方式完全一致。
注意:一個 SQL Map XML 映射文件可以包含任意多個 Mapped Statement,Parameter Map 和 Result Map。按照它們之間的邏輯關系,為您的應用合理地組織 Mapped Statement, Parameter Map 和 Result Map。SQL Map 的名稱是全局性的,在所有的 SQL Map 文件中名稱必須是唯一的。
- Mapped Statements
SQL Map 的核心概念是 Mapped Statement。Mapped Statement 可以使用任意的 SQL 語 句,並擁有 parameter map(輸入)和 result map(輸出)。如果是簡單情況,Mapped Statement 可以使用 Java 類來作為 parameter 和 result。Mapped Statement 也可以使用緩存模型,在內存 中緩存常用的數據。Mapped Statement 的結構如下所示:
1 <statement id=”statementName” [parameterClass=”some.class.Name”] [resultClass=”some.class.Name”] [parameterMap=”nameOfParameterMap”] [resultMap=”nameOfResultMap”] 2 [cacheModel=”nameOfCache”] 3 > 4 select * from PRODUCT where PRD_ID = [?|#propertyName#] 5 order by [$simpleDynamic$] 6 </statement>
- Statement的類型
<statement>元素是個通用聲明,可以用於任何類型的 SQL 語句。通常,使用具體的
statement 類型是個好主意。具體 statement 類型提供了更直觀的 XML DTD,並擁有某些
<statement>元素沒有的特性。下表總結了 statement 類型及其屬性和特性:
Statement 類型 |
屬性 |
子元素 |
方法 |
<statement> |
id parameterClass resultClass parameterMap resultMap cacheModel xmlResultName |
所有的動態元素 |
insert update delete 所有的查詢方法 |
<insert> |
id parameterClass parameterMap |
所有的動態元素 <selectKey> |
insert update delete |
<update> |
id parameterClass parameterMap |
所有的動態元素 |
insert update delete |
<delete> |
id parameterClass parameterMap |
所有的動態元素 |
insert update delete |
<select> |
id parameterClass resultClass parameterMap resultMap cacheModel |
所有的動態元素 |
所有的查詢方法 |
<procedure> |
id parameterClass resultClass parameterMap resultMap xmlResultName |
所有的動態元素 |
insert update delete 所有的查詢方法 |
- SQL 語句
SQL 顯然是 mapped statement 中最重要的部分,可以使用對於數據庫和 JDBC Driver 合 法的任意 SQL 語句。只要 JDBC Driver 支持,可以使用任意的函數,甚至是多條語句。因 為 SQL 語句是嵌在 XML 文檔中的,因此有些特殊的字符不能直接使用,例如大於號和小 於號(<>)。幸運的是,解決的辦法很簡單,只需將包含特殊字符的 SQL 語句放在 XML 的 CDATA 區里面就可以了。例如:
1 <statement id="getPersonsByAge" parameterClass=”int” 2 resultClass="examples.domain.Person"> 3 <![CDATA[ 4 SELECT * 5 FROM PERSON WHERE AGE > #value# 6 ]]> 7 </statement>
自動生成的主鍵
很多數據庫支持自動生成主鍵的數據類型。不過這通常(並不總是)是個私有的特性。 SQL Map 通過<insert>的子元素<selectKey>來支持自動生成的鍵值。它同時支持預生成(如 Oracle)和后生成兩種類型(如 MS-SQL Server)。
1 <!—Oracle SEQUENCE Example --> 2 <insert id="insertProduct-ORACLE" parameterClass="com.domain.Product"> 3 <selectKey resultClass="int" keyProperty="id" > 4 SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL 5 </selectKey> 6 insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) 7 values (#id#,#description#) 8 </insert> 9 <!— Microsoft SQL Server IDENTITY Column Example --> 10 <insert id="insertProduct-MS-SQL" parameterClass="com.domain.Product"> 11 insert into PRODUCT (PRD_DESCRIPTION) 12 values (#description#) 13 <selectKey resultClass="int" keyProperty="id" > SELECT @@IDENTITY AS ID 14 </selectKey> 15 </insert> 16 <!-- Mysql Auto Increased ID--> 17 <insert id="insertProduct-Mysql" parameterClass="com.domain.Product"> 18 insert into PRODUCT(PRD_DESCRIPTION) 19 values (#description#) 20 <selectKey resultClass="int" keyProperty="id"> 21 SELECT LAST_INSERT_ID() 22 </selectKey> 23 </insert>
存儲過程
SQL Map 通過<procedure>元素支持存儲過程。下面的例子說明如何使用具有輸出參數 的存儲過程。
1 <parameterMap id="swapParameters" class="map" > 2 <parameter property="email1" jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/> 3 <parameter property="email2" jdbcType="VARCHAR" javaType="java.lang.String" mode="INOUT"/> 4 </parameterMap> 5 <procedure id="swapEmailAddresses" parameterMap="swapParameters" > 6 {call swap_email_address (?, ?)} 7 </procedure>
調用上面的存儲過程將同時互換兩個字段(數據庫表)和參數對象(Map)中的兩個 email地址。如果參數的 mode 屬性設為 INOUT 或 OUT,則參數對象的值被修改。否則保持不變。
注意!要確保始終只使用 JDBC 標准的存儲過程語法。
- parameterClass
parameterClass 屬性的值是 Java 類的全限定名(即包括類的包名)。parameterClass 屬性 是可選的,但強烈建議使用。它的目的是限制輸入參數的類型為指定的 Java 類,並優化框 架的性能。如果您使用 parameterMap,則沒有必要使用 parameterClass 屬性。例如,如果要 只允許 Java 類“examples.domain.Product”作為輸入參數,可以這樣作:
1 <statement id=”statementName” parameterClass=” examples.domain.Product”> 2 insert into PRODUCT values (#id#, #description#, #price#) 3 </statement>
重要提示:雖然 2.0 向后兼容,但強烈建議使用 parameterClass(除非沒必要)。通過 提供 parameterClass,您可以獲得更好的性能,因為如果框架事先知道這個類,就可以優化 自身的性能。如果不指定 parameterClass 參數,任何帶有合適屬性(get/set 方法)的 Java Bean 都可 以作為輸入參數。
parameterMap
屬性 parameterMap 的值等於一個預先定義的<parameterMap>元素的名稱。parameterMap屬性很少使用,更多的是使用上的 parameterClass 和 inline parameter。
注意!動態 mapped statement 只支持 inline parameter,不支持 parameter map。
parameterMap 的基本思想是定義一系列有次序的參數系列,用於匹配 JDBC PreparedStatement 的值符號。
1 <parameterMap id=”insert-product-param” class=”com.domain.Product”> 2 <parameter property=”id”/> 3 <parameter property=”description”/> 4 </parameterMap> 5 <statement id=”insertProduct” parameterMap=”insert-product-param”> 6 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?); 7 </statement>
Inline Parameter簡介
現在簡單介紹一下 inline parameter,。Inline parameter 可以嵌在mapped statement 內部使用。例如:
1 <statement id=”insertProduct” > 2 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) 3 values (#id#, #description#); 4 </statement>
以上例子中,內嵌的參數是#id#和#description#。每個參數代表一個 Java Bean 屬性,用 於給 SQL 語句中相應的位置賦值。上面例子中,Product 對象的 id 和 description 屬性的值將 會替換 SQL 語句中相應的符號。因此,對於 id=5,description=‘dog’的 Product 對象,SQL 語句變為:
1 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) 2 values (5, ‘dog’);
resultClass
resultClass 屬性的值是 Java 類的全限定名(即包括類的包名)。resultClass 屬性可以讓 您指定一個 Java 類,根據 ResultSetMetaData 將其自動映射到 JDBC 的 ResultSet。只要是 Java Bean 的屬性名稱和 ResultSet 的列名匹配,屬性自動賦值給列值。這使得查詢 mapped statement 變得很短。例如:
1 <statement id="getPerson" parameterClass=”int” resultClass="examples.domain.Person"> SELECT PER_ID as id, 2 PER_FIRST_NAME as firstName, PER_LAST_NAME as lastName, PER_BIRTH_DATE as birthDate, PER_WEIGHT_KG as weightInKilograms, PER_HEIGHT_M as heightInMeters 3 FROM PERSON 4 WHERE PER_ID = #value# 5 </statement>
在上面的例子中,Person 類擁有屬性包括 id ,firstName ,lastName ,birthDate , weightInKilograms 和 heightInMeters。每一個屬性對應 SQL 查詢語句一個列的別名(使用“as” 關鍵字-標准的 SQL 語法)。一般情況下,列名和屬性名稱不匹配,就需要使用“as”關鍵 字。當執行 mapped statement 時,Person 類將被初始化,從結果集中得到的列值將根據屬性 名和列名映射成 Person 對象的屬性值。
正如以前所說,使用 resultClass 的自動映射存在一些限制,無法指定輸出字段的數據類型(如果需要的話),無法自動裝入相關的數據(復雜屬性),並且因為需要 ResultSetMetaData的信息,會對性能有輕微的不利影響。但使用 resultMap,這些限制都可以很容易解決。
- resultMap
resultMap 是最常用和最重要的屬性。ResultMap 屬性的值等於預先定義的 resultMap 元 素的 name 屬性值。使用 resultMap 可以控制數據如何從結果集中取出, 以及哪一個屬性匹配哪一個字段。不象使用 resultClass 的自動映射方法,resultMap 屬性可 以允許指定字段的數據類型,NULL 的替代值復雜類型映射(包括其他 Java Bean,集合類 型和基本類型包裝類)。
1 <resultMap id=”get-product-result” class=”com.ibatis.example.Product”> 2 <result property=”id” column=”PRD_ID”/> 3 <result property=”description” column=”PRD_DESCRIPTION”/> 4 </resultMap> 5 <statement id=”getProduct” resultMap=”get-product-result”> 6 select * from PRODUCT 7 </statement>
上面的例子中,通過 resultMap 的定義,查詢語句得到的 ResultSet 被映射成 Product 對 象。resultMap 定義的“id”屬性值將賦予“PRO_ID”字段值,而“description”屬性值將賦 予“PRD_DESCRIPTION”字段值。注意 resultMap 支持“select *”,並不要求定義 ResultSet 所有返回字段的映射。
-
cacheModel
cacheModel 的屬性值等於指定的 cacheModel 元素的 name 屬性值。屬性 cacheModel 定 義查詢 mapped statement 的緩存。每一個查詢 mapped statement 可以使用不同或相同的 cacheModel。
1 <cacheModel id="product-cache" imlementation="LRU"> 2 <flushInterval hours="24"/> 3 <flushOnExecute statement="insertProduct"/> 4 <flushOnExecute statement="updateProduct"/> 5 <flushOnExecute statement="deleteProduct"/> 6 <property name=”size” value=”1000” /> 7 </cacheModel> 8 <statement id=”getProductList” parameterClass=”int” cacheModel=”product-cache”> 9 select * from PRODUCT where PRD_CAT_ID = #value# 10 </statement>
上面例子中,“getProductList”的緩存使用 WEAK 引用類型,每 24 小時刷新一次,或 當更新的操作發生時刷新。
xmlResultName
當直接把查詢結果映射成 XML document 時,屬性 xmlResultName 的值等於 XML document 根元素的名稱。例如:
1 <select id="getPerson" parameterClass=”int” resultClass="xml" xmlResultName=”person”> SELECT PER_ID as id, 2 PER_FIRST_NAME as firstName, PER_LAST_NAME as lastName, PER_BIRTH_DATE as birthDate, PER_WEIGHT_KG as weightInKilograms, PER_HEIGHT_M as heightInMeters 3 FROM PERSON 4 WHERE PER_ID = #value# 5 </select>
上面的查詢結果將產生一個 XML document,結構如下:
1 <person> 2 <id>1</id> 3 <firstName>Clinton</firstName> 4 <lastName>Begin</lastName> 5 <birthDate>1900-01-01</birthDate> 6 <weightInKilograms>89</weightInKilograms> 7 <heightInMeters>1.77</heightInMeters> 8 </person>
- Parameter Map 和 Inline Parameter
如上所述,parameterMap 負責將 Java Bean 的屬性映射成 statement 的參數。雖然 parameterMap 的外部形式很少使用,理解它如何工作對於理解 inline parameter 還是很有幫助。
1 <parameterMap id=”parameterMapName” [class=”com.domain.Product”]> 2 <parameter property =”propertyName” [jdbcType=”VARCHAR”] [javaType=”string”] [nullValue=”NUMERIC”] [null=”-9999999”]/> 3 <parameter …… /> 4 <parameter …… /> 5 </parameterMap>
括號[]是可選的屬性。parameterMap 元素只要求屬性 id 作為唯一標識。屬性 class 是可選的但強烈推薦使用。和 parameterClass 類似,class 屬性可以框架檢查輸入參數的類型並優化性能。
<parameter>元素
一個 parameterMap 可包含任意多的 parameter 元素。以下討論 parameter 的各個屬性。
* property
屬性 property 是傳給 statement 的參數對象的 Java Bean 屬性名稱。該名稱根據需要,可 以在 statement 中多次出現(即在 SQL 語句 SET 子句中被更新的屬性,也可以作為條件出現 在 WHERE 子句中)。
* jdbcType
屬性 jdbcType 用於顯式地指定給本屬性(property)賦值的數據庫字段的數據類型。對 於某些特定的操作,如果不指定字段的數據類型,某些 JDBC Driver 無法識別字段的數據類 型。一個很好的例子是 PreparedStatement.setNull(int parameterIndex, int sqlType)方法,要求 指定數據類型。如果不指定數據類型,某些 Driver 可能指定為 Types.Other 或 Types.Null。 但是,不能保證所有的 Driver 都表現一致。對於這種情況,SQL Map API 允許使用 parameterMap 子元素 parameter 的 jdbcType 屬性指定數據類型。
正常情況下,只有當字段可以為 NULL 時才需要 jdbcType 屬性。另一需要指定 jdbcType 屬性的情況是字段類型為日期時間類型的情況。因為 Java 只有一個 Date 類型(java.util.Date), 而大多數 SQL 數據庫有多個-通常至少有 3 種。因此,需要指定字段類型是 DATE 還是 DATETIME。
屬性 jdbcType 可以是 JDBC Types 類中定義的任意參數的字符串值。雖然如此,還是有 某些類型不支持(即 BLOB)。本節的稍后部分會說明架構支持的數據類型。
注意!大多數 JDBC Driver 只有在字段可以為 NULL 時需要指定 jdbcType 屬性。因此, 對於這些 Driver,只是在字段可以為 NULL 時才需要指定 type 屬性。
注意!當使用 Oracle Driver 時,如果沒有給可以為 NULL 的字段指定 jdbcType 屬性, 當試圖給這些字段賦值 NULL 時,會出現“Invalid column type”錯誤。
* nullValue
屬性 nullValue 的值可以是對於 property 類型來說任意的合法值,用於指定 NULL 的替 換值。就是說,當 Java Bean 的屬性值等於指定值時,相應的字段將賦值 NULL。這個特性 允許在應用中給不支持 null 的數據類型(即 int,double,float 等)賦值 null。當這些數據類 型的屬性值匹配 null 值(即匹配-9999)時,NULL 將代替 null 值寫入數據庫。
1 <parameterMap id=”insert-product-param” class=”com.domain.Product”> 2 <parameter property=”id” jdbcType=”NUMERIC” javaType=”int” nullValue=”-9999999”/> 3 <parameter property=”description” jdbcType=”VARCHAR” nullValue=”NO_ENTRY”/> 4 </parameterMap> 5 <statement id=”insertProduct” parameterMap=”insert-product-param”> 6 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?); 7 </statement>
注意!parameterMap 並不自動地綁定到特定的 Java 類。因此在上面的例子中,任何擁 有“id”和“description”屬性的 Java Bean 對象,都可以作為 parameterMap 的輸入。如果 需要將輸入綁定到特定的 Java 類,可以使用 mapped-statement 的 resultClass 屬性。
注意!Parameter Map 的名稱(name)局部的,只在定義它的 SQL Map XML 文件中有 效。不過,加上 SQL Map 的名稱(即在<sqlMap>根元素中的名稱)作為前綴,您可以在另 一個 SQL Map XML 文件中引用它。例如,要在另一個文件中引用以上的 parameterMap,可 以使用名稱“Product.insert-product-param”。
Inline Parameter Map
parameterMap 的語法雖然簡單,但很繁瑣。還有一種更受歡迎更靈活的方法,可以大大簡化定義和減少代碼量。這種方法把 Java Bean 的屬性名稱嵌在 Mapped Statement 的定義中(即直接寫在 SQL 語句中)。缺省情況下,任何沒有指定 parameterMap 的 Mapped Statement都會被解析成 inline parameter(內嵌參數)。用上面的例子(即 Product)來說,就是:
1 <statement id=”insertProduct” parameterClass=”com.domain.Product”> 2 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) 3 values (#id#, #description#); 4 </statement>
在內嵌參數中指定數據類型可以用下面的語法:
1 <statement id=”insertProduct” parameterClass=”com.domain.Product”> 2 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) 3 values (#id:NUMERIC#, #description:VARCHAR#); 4 </statement>
在內嵌參數中指定數據類型和 NULL 的替代值可以用這樣的語法:
1 <statement id=”insertProduct” parameterClass=”com.domain.Product”> 2 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) 3 values (#id:NUMERIC:-999999#, #description:VARCHAR:NO_ENTRY#); 4 </statement>
注意!在內嵌參數中,要指定 NULL 的替代值,必須要先指定數據類型。 注意!如需要在查詢時也使用 NULL 替代值,必須同時在 resultMap 中定義(如下說明)。 注意!如果您需要指定很多的數據類型和 NULL 替代值,可以使用外部的 parameterMap元素,這樣會使代碼更清晰。
基本類型輸入參數
假如沒必要寫一個 Java Bean 作為參數,可以直接使用基本類型的包裝類(即 String,Integer,Date 等)作為參數。
1 <statement id=”insertProduct” parameter=”java.lang.Integer”> 2 select * from PRODUCT where PRD_ID = #value# 3 </statement>
假設 PRD_ID 的數據類型是 NUMERIC,要調用上面的 mapped statement,可以傳入一 個 java.lang.Integer 對象作為參數。Integer 對象的值將代替#value#參數。當使用基本類型包 裝類代替 Java Bean 時,切記要使用#value#作為參數。Result Map(參見以下章節)也支持 使用基本類型作為結果參數。
Map類型輸入參數
假如沒必要寫一個 Java Bean 作為參數,而要傳入的參數又不只一個時,可以使用 Map類(如 HashMap,TreeMap 等)作為參數對象。例如:
1 <statement id=”insertProduct” parameterClass=”java.util.Map”> 2 select * from PRODUCT 3 where PRD_CAT_ID = #catId# 4 and PRD_CODE = #code# 5 </statement>
Result Map
在 SQL Map 框架中,Result Map 是極其重要的組件。在執行查詢 Mapped Statement 時,resultMap 負責將結果集的列值映射成 Java Bean 的屬性值。resultMap 的結構如下:
1 <resultMap id=”resultMapName” class=”some.domain.Class” [extends=”parent-resultMap”]> 2 <result property=”propertyName” column=”COLUMN_NAME” [columnIndex=”1”] [javaType=”int”] [jdbcType=”NUMERIC”] [nullValue=”-999999”] [select=”someOtherStatement”] 3 4 /> 5 <result ……/> 6 <result ……/> 7 <result ……/> 8 </resultMap>
括號[]中是可選的屬性。resultMap 的 id 屬性是 statement 的唯一標識。ResultMap 的 class 屬性用於指定 Java 類的全限定名(即包括包的名稱)。該 Java 類初始化並根據定義填充 數據。extends 是可選的屬性,可設定成另外一個 resultMap 的名字,並以它為基礎。和在 Java 中繼承一個類相似,父 resultMap 的屬性將作為子 resutlMap 的一部分。父 resultMap 的屬性總是加到子 resultMap 屬性的前面,並且父 resultMap 必須要在子 resultMap 之前定義。父 resultMap 和子 resultMap 的 class 屬性不一定要一致,它們可以沒有任何關系。
resultMap 可以包括任意多的屬性映射,將查詢結果集的列值映射成 Java Bean 的屬性。 屬性的映射按它們在 resultMap 中定義的順序進行。相關的 Java Bean 類必須符合 Java Bean 規范,每一屬性都必須擁有 get/set 方法。
注意!ResultSet 的列值按它們在 resultMap 中定義的順序讀取(這特性會在某些實現得 不是很好的 JDBC Driver 中派上用場)。
esultMap 的 result 元素各個屬性:
property
屬性 property 的值是 mapped statement 返回結果對象的 Java Bean 屬性的名稱(get 方法)。
* column
屬性 column 的值是 ResultSet 中字段的名稱,該字段賦值給 names 屬性指定的 Java Bean 屬性。同一字段可以多次使用。注意,可能某些 JDBC Driver(例如,JDBC/ODBC 橋)不 允許多次讀取同一字段。
* columnIndex
屬性 columnIndex 是可選的,用於改善性能。屬性 columnIndex 的值是 ResultSet 中用於 賦值 Java Bean 屬性的字段次序號。在 99%的應用中,不太可能需要犧牲可讀性來換取性能。 使用 columnIndex,某些 JDBC Driver 可以大幅提高性能,某些則沒有任何效果.
* jdbcType
屬性 type 用於指定 ResultSet 中用於賦值 Java Bean 屬性的字段的數據庫數據類型(而 不是 Java 類名)。雖然 resultMap 沒有 NULL 值的問題,指定 type 屬性對於映射某些類型(例 如 Date 屬性)還是有用的。因為 Java 只有一個 Date 類型,而 SQL 數據庫可能有幾個(通 常至少有 3 個),為保證 Date(和其他)類型能正確的賦值,某些情況下指定 type 還是有必 要的。同樣地,String 類型的賦值可能來自 VARCHAR,CHAR 和 CLOB,因此同樣也有必 要指定 type 屬性(取決於 JDBC Driver)。
* javaType
屬性 javaType 用於顯式地指定被賦值的 Java Bean 屬性的類型。正常情況下,這可以通 過反射從 Java Bean 的屬性獲得,但對於某些映射(例如 Map 和 XML document),框架不能 通過這種方法來獲知。如果沒有設置 javaType,同時框架也不能獲知類型信息,類型將被假 定為 Object。
* nullValue
屬性 nullValue 指定數據庫中 NULL 的替代值。因此,如果從 ResultSet 中讀出 NULL值,Java Bean 屬性將被賦值屬性 null 指定的替代值。屬性 null 的值可以指定任意值,但必 須對於 Java Bean 屬性的類型是合法的。
* select
屬性 select 用於描述對象之間的關系,並自動地裝入復雜類型(即用戶定義的類型)屬 性的數據。屬性 select 的值必須是另外一個 mapped statement 元素的名稱。在同一個 result 元素中定義的數據庫字段(column 屬性)以及 property 屬性,將被傳給相關的 mapped statement 作為參數。因此,字段的數據類型必須是 SQL Map 支持的簡單數據類型。
隱式的Result Map
假如您有簡單的映射,不需要重用定義好的 resultMap,有一個快速的方法,就是通過 設定 mapped statement 的 resultClass 屬性來隱式地指定 result map。訣竅在於,保證返回的 ResultSet 的字段名稱(或標簽或別名)和 Java Bean 中可寫入屬性的名稱匹配。例如,考慮 以上的 Product 類,可以創建一個帶有隱式 result map 的 mapped statement 如下:
1 <statement id=”getProduct” resultClass=”com.ibatis.example.Product”> 2 select 3 PRD_ID as id, 4 PRD_DESCRIPTION as description from PRODUCT 5 where PRD_ID = #value# 6 </statement>
上面的 mapped statement 定義了 resultClass 屬性,並為每個字段指定了別名,用於匹配 Product 類的屬性名稱。這樣就可以了,不需要 result map。缺點在於,您無法指定字段的數據類型(通常不是 NULLABLE 字段不需要),或 NULL 替代值(或<result>別的屬性)。另外還要記住,數據庫很少是大小寫敏感的,因此隱式 result map 對大小寫也不敏感。假如您 的 Java Bean 有兩個屬性,一個是 firstName,另一個是 firstname,數據庫會把兩者看作同一 個屬性,因而不能使用隱式的 result map(這也可以看作是 Java Bean 設計的一個潛在問題)。 此外,使用 resultClass 的自動映射也對性能有輕微的不利影響。因為讀取 ResultSetMetaData 信息會使某些 JDBC Driver 變慢。
基本類型的Result(即String,Integer,Boolean)
除了支持符合 Java Bean 規范的 Java 類,Result Map 還可以給基本類型包裝類如 String, Integer,Boolean 等賦值。Result Map 還可以得到基本類型包裝類的集合。基本類型可以象 Java Bean 一樣映射,只是要記住一個 限制,基本類型只能有一個屬性,名字可以任意取(常用“value”或“val”)。例如,如果 您要獲得所有產品描述的一個列表而不是整個 Product 類,Result Map 如下:
1 <resultMap id=”get-product-result” class=”java.lang.String”> 2 <result property=”value” column=”PRD_DESCRIPTION”/> 3 </resultMap>
更簡單方法是,在 mapped statement 中使用 resultClass 屬性(使用“as”關鍵字給字段 取別名“value”):
1 <statement id=”getProductCount” resultClass=”java.lang.Integer”> 2 select count(1) as value from PRODUCT 3 </statement>
Map類型的Result
Result Map 也可以方便為一個 Map(如 HashMap 或 TreeMap)對象賦值。還可以得到 Map 對象的集合(即 Map 的 List)。 Map 對象與 Java Bean 同樣的方式映射,只是使用 name 屬性值作為 Map 的鍵值,用它來索 引相應的數據庫字段值,而不是象 Java Bean 一樣給屬性賦值。例如,如果您要將 Product 對象的數據裝入 Map,可以這樣做:
1 <resultMap id=”get-product-result” class=”java.util.HashMap”> 2 <result property=”id” column=”PRD_ID”/> 3 <result property=”code” column=”PRD_CODE”/> 4 <result property=”description” column=”PRD_DESCRIPTION”/> 5 <result property=”suggestedPrice” column=”PRD_SUGGESTED_PRICE”/> 6 </resultMap>
上面的例子會創建一個 HashMap 的實例並用 Product 的數據賦值。Property 的 name 屬性值(即“id”)作為 HashMap 的鍵值,而列值則作為 HashMap 中相應的值。 當然,可以把 Map 類型 Result 和隱式的 Result Map 一起使用。例如:
1 <statement id=”getProductCount” resultClass=”java.util.HashMap”> 2 select * from PRODUCT 3 </statement>
復雜類型屬性(即自定義類型的屬性)
因為 mapped statement 知道如何裝入合適的數據和 Java 類,通過將 resultMap 的 property 和相應的 mapped statement 聯系起來,可以自動地給復雜類型(即用戶創建的類)的屬性賦 值。復雜類型用以表示在數據庫中相互關系為一對一,一對多的數據。對於一對多的數據關 系,擁有復雜類型屬性的類作為“多”的一方,而復雜屬性本身則作為“一”的一方。考慮 下面的例子:
1 <resultMap id=”get-product-result” class=”com.ibatis.example.Product”> 2 <result property=”id” column=”PRD_ID”/> 3 <result property=”description” column=”PRD_DESCRIPTION”/> 4 <result property=”category” column=”PRD_CAT_ID” select=”getCategory”/> 5 </resultMap> 6 <resultMap id=”get-category-result” class=”com.ibatis.example.Category”> 7 <result property=”id” column=”CAT_ID”/> 8 <result property=”description” column=”CAT_DESCRIPTION”/> 9 </resultMap> 10 <statement id=”getProduct” parameterClass=”int” resultMap=”get-product-result”> 11 select * from PRODUCT where PRD_ID = #value# 12 </statement> 13 <statement id=”getCategory” parameterClass=”int” resultMap=”get-category-result”> 14 select * from CATEGORY where CAT_ID = #value# 15 </statement>
上面的例子中,Product 對象擁有一個類型為 Category 的 category 屬性。因為 category 是復雜類型(用戶定義的類型),JDBC 不知道如何給它賦值。通過將 category 屬性值和另 一個 mapped statement 聯系起來,為 SQL Map 引擎如何給它賦值提供了足夠的信息。通過 執行“getProduct”,“get-product-result”Result Map 使用 PRD_CAT_ID 字段的值去調用 “getCategory”。“get-category-result”Result Map 將初始化一個 Category 對象並賦值給它。 然后整個 Category 對象將賦值給 Product 的 category 屬性。
以上即SQL MAP XML的映射文件的詳細介紹。