iBATIS SQL Maps之Mapped Statements。

SQL Map的核心概念是Mapped Statement。Mapped Statement可以使用任意的SQL语句,并拥有parameter map(输入)和result map(输出)。如果是简单情况,Mapped Statement可以使用Java类来作为parameter和result。Mapped Statement也可以使用缓存模型,在内存中缓存常用的数据。Mapped Statement的结构如下所示:

<statement id = "statementName"

[parameterClass = "some.class.Name"]

[resultClass = "some.class.Name"]

[parameterMap = "nameOfParameterMap"]

[resultMap = "nameOfResultMap"]

[cacheModel = "nameOfCache"]

>

select * from PRODUCT where PRD_ID = [?|#propertyName#]

order by [$simpleDynamic$]

</statement>


在上面的表达式中,括号[]里的部分是可选的属性,并且在某些情况下只有特定的组合才是合法的。因此下面这个简单的例子也是正确的:

<statement id = "insertTestProduct">

insert into PRODUCT(PRD_ID, PRD_DESCRIPTION) values (1 , "Shih Tzu")

</statement>


上面的例子不太可能出现,但如果只是简单地想用SQL Map架构来执行任意的的SQL语句,这种写法就派上用场了。但常见的用法还是通过Parameter Map和Result Map,来实现Java Bean映射的特性,这是SQL Map真正有价值的地方。


  • Statement的类型
<statement>元素是个通用声明,可以用于任何类型的SQL语句。通常,使用具体的statement类型是个好主意。具体statement类型提供了更直观的XML DTD,并拥有某些<statement>元素没有的特性。下表总结了Statement类型及其属性和特性:

  • SQL语句
SQL显然是mapped statement中最重要的部分,可以使用对于数据库和JDBC Driver合法的任意SQL语句。只要JDBC Driver支持,可以使用任意的函数,甚至是多条语句。 因为SQL语句是嵌在XML文档中的,因此有些特殊的字符不能直接使用,例如大于号和小于号(<>)。幸运的是,解决的方法很简单,只需将博爱涵特殊字符的SQL语句放在XML的CDATA区里面就可以了。例如:
<statement id = "getPersonsByAge" parameterClass = "int" resultClass = "examples.domain.Person">
<![CDATA[
SELECT *
FROM PERSON
WHERE AGE > #value#
]]>
</statement>

  • 自动生成的主键
很多数据库支持自动生辰主键的数据类型。不过这通常(并不总是)是个私有的特性。
SQL Map通过<insert>的子元素<selectKey>来支持自动生成的键值。他同时支持预生成(Oracle)和后生成两种类型(如MS-SQL Server)。下面是两个例子:
<! -- Oracle SEQUENCE Example -->
<insert id ="insertProduct-ORACLE" parameterClass = "com.domain.Product" >
<selectKey resultClass = "int" keyProperty = "id">
SELECT STOCKID SEQUENCE.NEXTVAL AS ID FROM DUAL
</selectKey>
insert into PRODUCT(PRD_ID, PRD_DESCRIPTION)
value (#id#, #description#)
</insert>

<!-- Microsoft SQL Server IDENTITY Column Example -->
<insert id = "insertProduct-MS-SQL" parameterClass = "com.domain.Product">
insert into PRODUCT (PRD_DESCRIPTION)
values(#description#)
<selectKey resultClass = "int" keyProperty = "id">
SELECT @@IDENTITY AS ID
</selectKey>
</insert>

  • 存储过程
SQL Map通过<procedure>元素支持存储过程。下面的例子说明如何使用具有输出参数的存储过程。
<parameterMap id = "swapParameters" class = "map">
<parameter property = "email1" jdbcType = "VARCHAR" javaType = "java.lang.String" mode = "INOUT" />
<parameter property = "email2" jdbcType = "VARCHAR" javaType = "java.lang.String" mode = "INOUT" />
</parametermap>
<procedure id = "swapEmailAddresses" parameterMap = "" >
{call swap_email_address(? , ?)}
</procedure>
调用上面的存储过程将同时互换两个字段(数据库表)和参数对象(Map)中的两个email地址。如果参数的mode属性设为INOUT或OUT,则参数对象的值被修改。否则保持不变。
注意!要确保始终只使用JDBC标准的存储过程语法。参考JDBC的CallableStatement文档以获得更详细的信息。

  • parameterClass
parameterClass属性的值是Java类的全限定名(即包括类的包名)。parameterClass属性是可选的,但强烈建议使用。它的目的是限制输入参数的类型为指定的Java类,并优化框架的性能。它的目的是限制输入参数的类型为指定的Java类,并优化框架的性能。如果您使用parameterMap,则没有必要使用parameterClass属性。例如,如果要只允许Java类“examples.domain.Product”作为输入参数,可以这样做:
<statement id = "statementName" parameterClass = "examples.domain.Product">
insert into PRODUCT values (#id#, #description#, #price#)
</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的值符号。例如:
<parameterMap id = "insert-product-param" class = "com.domain.Product">
<parameter property = "id" />
<parameter property = "description" />
</parameterMap>
<statement id = "insertProduct" parameterMap = "insert-product-param" >
insert into PRODUCT(PRD_ID, PRD_DESCRIPTION) values (?,?);
</statement>
上面的例子中,parameter map的两个参数按次序匹配SQL语句中的值符号(?)。因此,第一个“?”号将被“id”属性的值替换,而第二个“?”号将被“description”属性的值替换。

  • Inline Parameter简介
现在简单介绍一下inline parameter。Inline parameter可以嵌在mapped statement内部使用。例如:
<statement id = "insertProduct">
insert into PRODUCT(PRD_ID, PRD_DESCRIPTION) values (#id#, #description#);
</statement>
以上例子中,内嵌的参数是#id#和#description#。每个参数代表一个Java Bean属性,用于给SQL语句中相应的位置赋值。上面例子中,Product对象的id和description属性的值将会替换SQL语句中相应的符号。因此,对于id =5,description='dog'的Product对象,SQL语句将变为:
insert into PRODUCT(PRD_ID, PRD_DESCRIPTION) values (5, 'dog');

  • resultClass
resultClass属性的值是Java类的全限定名(即包括类的包名) 。resultClass属性可以让您指定一个Java类,根据ResultSetMetaData将其自动映射到JDBC的ResultSet。只要Java Bean的属性名称和ResultSet的列名匹配,属性自动赋值给列值。这使得查询mapped statement变得很短。例如:
<statement id = "getPerson" parameterClass = "int" resultClass = "examples.domain.Person">
SELECT PER_ID as id,
PER_FIRST_NAME as firstName,
PER_LAST_NAME as lastName,
PER_BIRTH_NAME as birthDate,
PER_WEIGHT_KG as weightInKilograms,
PER_HEIGHT_M as heightInMeters
FROM PERSON
WHERE PER_ID = #value#
</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的替代之复杂类型映射(包括其他JavaBean,集合类型和基本类型包装类)。
<resultMap id = "get-product-result" class = "com.ibatis.example.Product">
<result property = "id" column = "PRD_ID">
<result property = "description" column = "PRD+DESCRIPTION" / >
</resultMap>
<statement id = "getProduct" resultMap = "get-product-result">
select * from PRODUCT
</statement>
上面的例子中,通过resultMap的定义,查询语句得到的ResultSet被映射成Product对象。resultMap定义的“id” 属性值将被赋予“PRO_ID”字段值,而“description”属性值将赋予“PRD_DESCRIPTION”字段值。注意resultMap支持“select *”,并不要求定义ResultSet所有返回字段的映射。

  • cacheModel
cacheModel的属性值等于指定cacheModel元素的name属性值。属性cacheModel定义查询mapped statement的缓存。每一个查询mapped statement可以使用不同或相同的cacheModel。
<cacheModel  id = "product-cache" imlementation = "LRU">
<flushInterval hours = '24" />
<flushOnExecute statement = "insertProduct" />
<flushOnExecute statement = "updateProduct" />
<flushOnExecute statement = "deleteProduct" />
<property name = "size" value = "1000" />
</cacheModel>
<statement id = "getProductList" parameterClass = "int" cacheModel = "product-cache">
select * from PRODUCT where PRD_CAT_ID = #value#
</statement>
上面例子中,“getProductList”的缓存使用WEAK引用类型,每24小时刷新一次,或当更新的操作发生时刷新。

  • xmlResultName
当直接把查询结果映射成XML doucment时,属性xmlResultName的值等于XML document根元素的名称。例如:
<select id = "getPerson" parameterClass = "int"  resultClass = "xml" xmlResultName = "person">
SELECT PER_ID as id,
PER_FIRST_NAME as firstName,
PER_LAST_NAME as lastName,
PER_BIRTH_NAME as birthDate,
PER_WEIGHT_KG as weightInKilograms,
PER_HEIGHT_M as heightInMeters
FROM PERSON
WHERE PER_ID = #value#
</select>
上面的查询结果将产生一个XML document,结构如下:
<person>
<id>1</id>
<firstName>Clinton</firstName>
<lastName>Begin</lastName>
<birthDate>1900-01-01</birthDate>
<weightInKilograms>89</weightInKilograms>
< heightInMeters>1.77</ heightInMeters>
</person>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值