Ibatis学习总结3--SQL Map XML 映射文件

 

在前面的例子中,只使用了 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的映射文件的详细介绍。

posted @ 2016-01-05 00:00  ngulc  阅读(7814)  评论(1编辑  收藏  举报