注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

断尘居

温柔的男人像海洋。

 
 
 
 
 

日志

 
 

ibatis 开发指南(三)  

2010-09-17 03:37:05|  分类: SSH |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

ibatis 基础语义:
XmlSqlMapClientBuilder 
 XmlSqlMapClientBuilder 是ibatis 2.0 之后版本新引入的组件,用以替代1.x 版本中的XmlSqlMapBuilder。其作用是根据配置文件创建SqlMapClient 实例。
SqlMapClient 
 SqlMapClient 是ibatis 的核心组件,提供数据操作的基础平台。SqlMapClient可通过XmlSqlMapClientBuilder 创建: 
  String resource ="com/ibatis/sample/SqlMapConfig.xml"; 
  Reader reader; 
  reader = Resources.getResourceAsReader(resource); 
  XmlSqlMapClientBuilder xmlBuilder =new XmlSqlMapClientBuilder(); 
  SqlMapClient sqlMap = xmlBuilder.buildSqlMap(reader);

 "com/ibatis/sample/SqlMapConfig.xml"指明了配置CLASSPATH文件在中的相对路径。XmlSqlMapClientBuilder 通过接受一个Reader 类型的配置文
 件句柄,根据配置参数,创建SqlMapClient 实例。

SqlMapClient 提供了众多数据操作方法,下面是一些常用方法的示例,具体说明文档请参见ibatis java doc,或者ibatis 官方开发手册。
SqlMapClient 基本操作示例
以下示例摘自ibatis 官方开发手册,笔者对其进行了重新排版以获得更好的阅读效果。

例1: 数据写入操作(insert, update, delete): 
sqlMap.startTransaction(); 
Product product = new Product(); 
product.setId (1); 
product.setDescription (“Shih Tzu”);
int rows = sqlMap.insert (“insertProduct”, product); 
sqlMap.commitTransaction(); 

例2: 数据查询(select) 
sqlMap.startTransaction(); 
Integer key = new Integer (1); 
Product product = (Product)sqlMap.queryForObject(“getProduct”, key); 
sqlMap.commitTransaction(); 

例3: 在指定对象中存放查询结果(select) 
sqlMap.startTransaction(); 
Customer customer = new Customer(); 
sqlMap.queryForObject(“getCust”, parameterObject, customer); 
sqlMap.queryForObject(“getAddr”, parameterObject, customer); 
sqlMap.commitTransaction(); 

例4: 执行批量查询(select) 
sqlMap.startTransaction(); 
List list = sqlMap.queryForList (“getProductList”, null); 
sqlMap.commitTransaction(); 

例5: 关于AutoCommit 
//没有预先执行startTransaction时,默认为模式
int rows = sqlMap.insert (“insertProduct”, product); 
auto_commit 

例6:查询指定范围内的数据
sqlMap.startTransaction(); 
null= "";
sqlMap.commitTransaction(); 
List list sqlMap.queryForList (getProductList, 0, 40); 

例7: 结合RowHandler 进行查询(select) 
MyRowHandler implements RowHandler { 
handleRow (Object object, List list) throws 
SQLException { 
Product product = (Product) object; 
product.setQuantity (10000); 
sqlMap.update (“updateProduct”, product); 


sqlMap.startTransaction(); 
RowHandler rowHandler = new MyRowHandler(); 
List list = sqlMap.queryForList (“getProductList”, null, 
rowHandler); 
sqlMap.commitTransaction(); 
public classpublic void

例8: 分页查询(select) 
PaginatedList list = 
sqlMap.queryForPaginatedList (“getProductList”, null, 10); 
list.nextPage(); 
list.previousPage(); 

例9: 基于Map 的批量查询(select) 
sqlMap.startTransaction(); 
Map map = sqlMap.queryForMap (“getProductList”, null, 
“productCode”); 
sqlMap.commitTransaction(); 
Product p = (Product) map.get(“EST-93”); 

OR 映射
相对Hibernate 等ORM 实现而言,ibatis 的映射配置更为简洁直接,下面是一个典型的配置文件。
<!DOCTYPE sqlMap
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap namespace="User">
<!--模块配置--> 
<typeAlias alias="user" type="com.ibatis.sample.User"/>
<cacheModel id="userCache" type="LRU">
<flushInterval hours="24"/> 
<flushOnExecute statement=" updateUser"/>
<property name="size" value="1000" />
</cacheModel>
<!—Statement配置--> 
<select id="getUser"
parameterClass="java.lang.String"
resultClass="user" 
cacheModel="userCache"
>
<![CDATA[
select 
name, 
sex 
from t_user 
where name = #name# 
]]>
</select> 
<update id="updateUser"
parameterClass="user">
UPDATE t_user 
SET
name=#name#, 
sex=#sex# 
WHERE id = #id# 
</update> 

</sqlMap> 
可以看到,映射文件主要分为两个部分:模块配置和Statement 配置。模块配置包括: 
 . typeAlias 节点:定义了本映射文件中的别名,以避免过长变量值的反复书写,此例中通过typeAlias 节点为类"com.ibatis.sample.User"定义了一个别   名"user", 这样在本配置文件的其他部分,需要引用"com.ibatis.sample.User" 类时,只需以其别名替代即可。
 . cacheModel 节点: 定义了本映射文件中使用的Cache 机制
  <cacheModel id="userCache" type="LRU"> 
   <flushInterval hours="24"/> 
   <flushOnExecute statement="updateUser"/> 
   <property name="size" value="1000" /> 
  </cacheModel> 
这里申明了一个名为"userCache" 的,之后可以在cacheModel Statement 申明中对其进行引用:
<select id="getUser" parameterClass="java.lang.String" resultClass="user" cacheModel="userCache">
这表明对通过id 为"getUser"的获取的数据,使用Select statement 
cacheModel "userCache" 进行缓存。之后如果程序再次用此Statement 
进行数据查询,即直接从缓存中读取查询结果,而无需再去数据库查询。
cacheModel 主要有下面几个配置点: 
. flushInterval : 设定缓存有效期,如果超过此设定值,则将此CacheModel 的缓存清空。
. size: 本CacheModel 中最大容纳的数据对象数量。
. flushOnExecute: 指定执行特定Statement 时,将缓存清空。如updateUser 操作将更新数据库中的用户信息,这将导致缓存中的数据对象与数据库中的实际
数据发生偏差,因此必须将缓存清空以避免脏数据的出现。
关于Cache 的深入探讨,请参见“高级特性”中的相关章节。
Statement 配置: 

Statement 配置包含了数个与SQL Statement 相关的节点,分别为: 
. statement 
. insert 
. delete 
. update 
. select 
. procedure 
其中,statement 最为通用,它可以替代其余的所有节点。除statement 之外的节点各自对应了SQL 中的同名操作(procedure 对应存储过程)。
使用statement 定义所有操作固然可以达成目标,但缺乏直观性,建议在实际开发中根据操作目的,各自选用对应的节点名加以申明。一方面,使得配置文件
更加直观,另一方面,也可借助DTD 对节点申明进行更有针对性的检查,以避免配置上的失误。
各种类型的Statement 配置节点的参数类型基本一致,区别在于数量不同。如insert、update、delete 节点无需返回数据类型定义(总是int)。
主要的配置项如下:

statement: 
<statement id="statementName" [parameterClass="some.class.Name"] [resultClass="some.class.Name"] [parameterMap="nameOfParameterMap"] 
[resultMap="nameOfResultMap"] [cacheModel="nameOfCache"] > 
select * from t_user where sex = [?|#propertyName#] order by [$simpleDynamic$] 
</statement> 

select: 
<select id="statementName" [parameterClass="some.class.Name"] [resultClass="some.class.Name"] [parameterMap="nameOfParameterMap"] 
[resultMap="nameOfResultMap"] [cacheModel="nameOfCache"] > 
select * from t_user where sex = [?|#propertyName#] order by [$simpleDynamic$] 
</select> 

Insert: 
<insert id="statementName" [parameterClass="some.class.Name"] [parameterMap="nameOfParameterMap"]>
insert into t_user(name,sex) values([?|#propertyName#],[?|#propertyName#]) 
</insert> 

Update: 
<update id="statementName" [parameterClass="some.class.Name"] [parameterMap="nameOfParameterMap"]>
UPDATE t_user SET name=[?|#propertyName#], sex=[?|#propertyName#] WHERE id = [?|#propertyName#] 
</update> 

Delete: 
<delete id="statementName" [parameterClass="some.class.Name"] [parameterMap="nameOfParameterMap"]>
delete from t_user where id = [?|#propertyName#] 
</delete> 

其中以“[]”包围的部分为可能出现的配置栏目。
参数描述
parameterClass 参数类。指定了参数的完整类名(包括包路径)。可通过别名避免每次重复书写冗长的类名。
resultClass 结果类。指定结果类型的完整类名(包括包路径) 可通过别名避免每次重复书写冗长的类名。
parameterMap 参数映射,需结合parameterMap 节点对映射关系加以定义。对于存储过程之外的statement 而言,建议使用parameterClass 作为参数配置方式, 一方面避免了参数映射配置工作,另一方面其性能表现也更加出色。
resultMap 结果映射,需结合resultMap 节点对映射关系加以定义。
cacheModel statement 对应的Cache 模块。
对于参数定义而言,尽量使用parameterClass,即直接将POJO 作为
statement 的调用参数,这样在SQL 中可以直接将POJO 的属性作为参数加以设定,如:
<update id="updateUser" parameterClass="com.ibatis.sample.User">
UPDATE t_user SET name=#name#, sex=#sex# WHERE id = #id# 
</update> 
这里将com.ibatis.sample.User 类设定为的参数,之后,update statement 我们即可在SQL 中通过#propertyName#对POJO 的属性进行引用。如上例中的:
SET name=#name#, sex=#sex# WHERE id=#id# 
运行期,将通过调用对象的、和方法获得相ibatis User getName getSex getId 应的参数值,并将其作为SQL 的参数。
如果parameterClass 中设定的是jdk 的中的简单对象类型,如String、
Integer,ibatis 会直接将其作为SQL 中的参数值。
我们也可以将包含了参数数据的Map 对象传递给Statement ,如:
<update id="updateUser" parameterClass="java.util.Map">
UPDATE t_user SET name=#name#, sex=#sex# WHERE id = #id# 
</update> 
这里传入的参数就是一个对象,将以””、””、”id”从中Map ibatis key namesex提取对应的参数值。
同样的原理,我们也可以在resultMap 中设定返回类型为map 。
<select id="getUser" parameterClass="java.lang.String" resultClass="java.util.Map"> 
<![CDATA[
select id, name, sex from t_user where id = #id# 
]]>
</select>
返回的结果将以各字段名为保存在对象中返回。key Map 在SQL 中设定参数名时,可以同时指定参数类型, 如:
SET name=#name:VARCHAR#,sex=#sex:NUMERIC# WHERE id=#id:NUMERIC# 
对于返回结果而言,如果是select 语句,建议也采用resultClass 进行定义,如:
<select id="getUser" parameterClass="java.lang.String" resultClass="user">
<![CDATA[
select name, sex from t_user where name = #name# 
]]>
</select> 
会自动根据语句中的字段名,调用对应的方法设定属性ibatis select POJO set 
值,如上例中,ibatis 会调用setName,setSex 方法将Select 语句返回的数据赋
予相应的POJO 实例。
有些时候,数据库表中的字段名过于晦涩,而为了使得代码更易于理解,我们
希望字段映射到POJO 时,采用比较易读的属性名,此时,我们可以通过Select 
的as 字句对字段名进行转义,如(假设我们的书库中对应用户名的字段为
xingming ,对应性别的字段为xingbie): 
select 
xingming as name, 
xingbie as sex 
from t_user 
where id = #id# 
会根据转义后的字段名进行属性映射(即调用的方法而ibatis POJO setName 
不是setXingming 方法)。

parameterMap 和resultMap 实现了POJO 到数据库字段的映射配置,下面是
一个例子: 
<resultMap id="get_user_result" class="user"> 
<result property="name" column="xingming" 
jdbcType="VARCHAR" javaType="java.lang.String"/> 
<result property="sex" column="xingbie" 
jdbcType="int" javaType="java.lang.Integer"/> 
<result property="id" column="id" 
jdbcType="int" javaType="java.lang.Integer"/> 
</resultMap> 
<parameterMap id="update_user_para" class="redemption" > 
<parameter property="name" 
jdbcType="VARCHAR" 
javaType="java.lang.String" 
nullValue="" 
/> 
<parameter property="sex" 
jdbcType="int" 
javaType="java.lang.Integer" 
nullValue="" 
/> 
</parameterMap> 
Parameter 的nullValue 指定了如果参数为空(null)时的默认值。
之后我们即可在statement 申明中对其进行引用,如:
<procedure id="getUserList"
resultMap="get_user_result"

{call sp_getUserList()} 
</procedure> 
<procedure id="doUserUpdate"
parameterMap="update_user_para"

{call sp_doUserUpdate(#id#,#name#,#sex#)} 
</procedure> 
一般而言,对于insert 、update 、delete 、select 语句,优先采用parameterClass 
和resultClass 。
parameterMap 使用较少,而resultMap 则大多用于嵌套查询以及存储过程的

处理,之所以这样,原因是由于存储过程相对而言比较封闭(很多情况下需要调用现有
的存储过程,其参数命名和返回的数据字段命名往往不符合Java 编程中的命名习惯, 
并且由于我们难以通过Select SQL 的as子句进行字段名转义,无法使其自动与POJO 
中的属性名相匹配)。此时,使用resultMap 建立字段名和POJO 属性名之间的映射
关系就显得非常有效。另一方面,由于通过resultMap 指定了字段名和字段类型, 
ibatis 无需再通过JDBC ResultSetMetaData 来动态获取字段信息,在一定程度
上也提升了性能表现。
ibatis 高级特性
数据关联
至此,我们讨论的都是针对独立数据的操作。在实际开发中,我们常常遇到关联数
据的情况,如User 对象拥有若干Address 对象,每个Address 对象描述了对应User 的
一个联系地址,这种情况下,我们应该如何处理? 
通过单独的Statement 操作固然可以实现(通过Statement 用于读取用户数据,再手
工调用另外一个Statement 根据用户ID 返回对应的Address 信息)。不过这样未免失之
繁琐。下面我们就看看在ibatis 中,如何对关联数据进行操作。
ibatis 中,提供了Statement 嵌套支持,通过Statement 嵌套,我们即可实现关联数
据的操作。
一对多关联
下面的例子中,我们首选读取t_user 表中的所有用户记录,然后获取每个用户对应
的所有地址信息。
配置文件如下:
<sqlMap namespace="User"> 
<typeAlias alias="user" type="com.ibatis.sample.User"/> 
<typeAlias alias="address" type="com.ibatis.sample.Address"/> 
<resultMap id="get-user-result" class="user"> 
<result property="id" column="id"/> 
<result property="name" column="name"/> 
<result property="sex" column="sex"/> 
<result property="addresses" column="id" 
select="User.getAddressByUserId"/> 
</resultMap> 
<select id="getUsers" 
parameterClass="java.lang.String" 
resultMap="get-user-result"> 
<![CDATA[ 
select 
id, 

name, 
sex 
from t_user 
where id = #id# 
]]>
</select>
<select id="getAddressByUserId"
parameterClass="int"
resultClass="address">
<![CDATA[
select 
address, 
zipcode 
from t_address 
where user_id = #userid# 
]]>
</select>
</sqlMap>
对应代码:
String resource ="com/ibatis/sample/SqlMapConfig.xml"; 
Reader reader; 
reader = Resources.getResourceAsReader(resource); 
XmlSqlMapClientBuilder xmlBuilder= new XmlSqlMapClientBuilder(); 
sqlMap = xmlBuilder.buildSqlMap(reader); 
//sqlMap系统初始化完毕
List userList = sqlMap.queryForList("User.getUsers", ""); 
for (int i = 0; i < userList.size(); i++) { 
User user = (User)userList.get(i);
System.out.println("==>" + user.getName()); 
for (int k = 0; k < user.getAddresses().size(); k++) { 
Address addr = (Address) user.getAddresses().get(k); 
System.out.println(addr.getAddress()); 

这里通过在resultMap 中定义嵌套查询getAddressByUserId,我们实现了关联
数据的读取。
实际上,这种方式类似于前面所说的通过两条单独的Statement 进行关联数据的读
取,只是将关联关系在配置中加以描述,由ibatis 自动完成关联数据的读取。
需要注意的是,这里有一个潜在的性能问题,也就是所谓“n+1”Select 问题。
注意上面示例运行过程中的日志输出: 
…… 
PreparedStatement -{pstm-100001} PreparedStatement: select id, name, sex from 
t_user 
…… 
PreparedStatement -{pstm-100004} PreparedStatement: select address, zipcode from 
t_address where user_id = ? 
…… 
PreparedStatement -{pstm-100007} PreparedStatement: select address,zipcode from 
t_address where user_id = ? 
第一条将表中的所有数据读取出来PreparedStatement t_user (目前t_user 表中有两
条测试数据),随即,通过两次Select 操作,从t_address 表中读取两个用户所关联的
Address 记录。
如果t_user 表中记录较少,不会有明显的影响,假设t_user 表中有十万条记录,那
么这样的操作将需要100000+1 条Select 语句反复执行才能获得结果,无疑,随着记录
的增长,这样的开销将无法承受。
之所以在这里提及这个问题,目的在于引起读者的注意,在系统设计中根据具体情
况,采用一些规避手段(如使用存储过程集中处理大批量关联数据),从而避免因为这
个问题而引起产品品质上的缺陷。
一对一关联
一对一关联是一对多关联的一种特例。这种情况下,如果采用上面的示例将导致
1+1 条SQL 的执行。
对于这种情况,我们可以采用一次Select 两张表的方式,避免这样的性能开销(假
设上面示例中,每个User 只有一个对应的Address 记录): 
<resultMap id="get-user-result" class="user"> 
<result property="id" column="id"/> 
<result property="name" column="name"/> 
<result property="sex" column="sex"/> 
<result property="address" column="t_address.address"/> 
<result property="zipCode" column="t_address.zipcode"/> 
</resultMap> 
<select id="getUsers" 
parameterClass="java.lang.String" 
resultMap="get-user-result"> 
<![CDATA[ 
select 


from t_user,t_address
where t_user.id=t_address.user_id 
]]>
</select>
与此同时,应该保证类中包含和两个型属性。User address zipCode String 

延迟加载
在运行上面的例子时,通过观察期间的日志输出顺序我们可以发现,在我们执行
sqlMap.queryForList("User.getUsers", "")时,实际上ibatis 只向数据库发送
了一条select id, name, sex from t_user SQL 。而用于获取Address 记录的SQL,只有在我
们真正访问address 对象时,才开始执行。
这也就是所谓的延迟加载(Lazy Loading)机制。即当真正需要数据的时候,才加
载数据。延迟加载机制能为我们的系统性能带来极大的提升。
试想,如果我们只需要获取用户名称和性别数据,在没有延迟加载特性的情况下,
ibatis 会一次将所有数据都从数据库取回,包括用户信息及其相关的地址数据,而此时,
关于地址数据的读取操作没有意义,也就是说,我们白白在地址数据的查询读取上浪费
了大量的系统资源。延迟加载为我们妥善的处理了性能与编码上的平衡(如果没有延迟
加载,我们为了避免无谓的性能开销,只能专门为此再增加一个不读取地址信息的用户
记录检索模块,无疑增加了编码上的工作量)。
回忆之前“ibatis 配置”中的内容: 
<settings ⑴ 
……
enhancementEnabled="true"
lazyLoadingEnabled="true"
……
/>
节点有两个与延迟加载相关的属性lazyLoadingEnabled 和Settings 
enhancementEnabled,其中lazyLoadingEnabled 设定了系统是否使用延迟加载
机制,enhancementEnabled 设定是否启用字节码强化机制(通过字节码强化机制可
以为Lazy Loading 带来性能方面的改进。
为了使用延迟加载所带来的性能优势,这两项都建议设为"true"。

动态映射
在复杂查询过程中,我们常常需要根据用户的选择决定查询条件,这里发生变化的
并不只是SQL 中的参数,包括Select 语句中所包括的字段和限定条件,都可能发生变
化。典型情况, 如在一个复杂的组合查询页面,我们必须根据用户的选择和输入决定查
询的条件组合。
一个典型的页面如下:
对于这个组合查询页面,根据用户选择填写的内容,我们应为其生成不同的查询语
句。
如用户没有填写任何信息即提交查询请求,我们应该返回所有记录: 
Select * from t_user; 
如用户只在页面上填写了姓名“Erica”,我们应该生成类似:
Select * from t_user where name like ‘%Erica%’ ;
的SQL 查询语句。
如用户只在页面上填写了地址“Beijing”,我们应该生成类似:
Select * from t_user where address like ‘%Beijing%”;
的SQL 。
而如果用户同时填写了姓名和地址(”Erica”&’Beijing’),则我们应生成类似: 
Select * from t_user where name like ‘%Erica%’ and address like ‘%Beijing%” 
的SQL 查询语句。
对于ibatis 这样需要预先指定SQL 语句的ORM 实现而言,传统的做法无非通过
if-else 语句对输入参数加以判定,然后针对用户选择调用不同的statement 定义。对于
上面这种简单的情况(两种查询条件的排列组合,共4 种情况)而言,statement 的重
复定义工作已经让人不厌其烦,而对于动辄拥有七八个查询条件,乃至十几个查询条件
的排列组合而言,琐碎反复的statement 定义实在让人不堪承受。
考虑到这个问题,ibatis 引入了动态映射机制,即在statement 定义中,根据不同的
查询参数,设定对应的SQL 语句。
还是以上面的示例为例: 
<select id="getUsers"
parameterClass="user"
resultMap="get-user-result">

select 
id, 
name, 
sex 
from t_user 
<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="name">
(name like #name#) 
</isNotEmpty>
<isNotEmpty prepend="AND" property="address">
(address like #address#) 
</isNotEmpty>
</dynamic>
</select>
通过dynamic 节点,我们定义了一个动态的WHERE 子句。此WHERE 子句中将
可能包含两个针对name 和address 字段的判断条件。而这两个字段是否加入检索取决
于用户所提供的查询条件(字段是否为空[isNotEmpty])。
对于一个典型的Web 程序而言,我们通过HttpServletRequest 获得表单中的字段名
并将其设入查询参数,如:
user.setName(request.getParameter("name")); 
user.setAddress(request.getParameter("address")); 
sqlMap.queryForList("User.getUsers", user); 
在执行queryForList("User.getUsers", user) 时,ibatis 即根据配置文
件中设定的SQL 动态生成规则,创建相应的SQL 语句。
上面的示例中,我们通过判定节点isNotEmpty,指定了关于name 和address 属
性的动态规则: 
<isNotEmpty prepend="AND" property="name"> 
(name like #name#) 
</isNotEmpty> 
这个节点对应的语义是, 如果参数类的"name"属性非空(isNotEmpty,即非空
字符串””),则在生成的SQL Where 字句中包括判定条件(name like #name#),其
中#name#将以参数类的name 属性值填充。
Address 属性的判定生成与name 属性完全相同,这里就不再赘述。

这样,我们通过在statement 定义中引入dynamic 节点,很简单的实现了SQL 判
定子句的动态生成,对于复杂的组合查询而言,这将带来极大的便利。
判定节点的定义可以非常灵活,我们甚至可以使用嵌套的判定节点来实现复杂的动
态映射, 如:
<isNotEmpty prepend="AND" property="name"> 
( name=#name# 
<isNotEmpty prepend="AND" property="address"> 
address=#address#
</isNotEmpty> 

</isNotEmpty> 
这段定义规定,只有用户提供了姓名信息时,才能结合地址数据进行查询(如果只
提供地址数据,而将姓名信息忽略,将依然被视为全检索)。
Dynamic 节点和判定节点中的prepend 属性,指明了本节点中定义的SQL 子句在
主体SQL 中出现时的前缀。
如:
<dynamic prepend="WHERE">
<isNotEmpty prepend="AND" property="name">
(name like #name#) 
</isNotEmpty>
<isNotEmpty prepend="AND" property="address">
(address like #address#) 
</isNotEmpty>
</dynamic>
假设"name"属性的值为“Erica”, "address"属性的值为“Beijing”,则会
生成类似下面的SQL 子句(实际运行期将生成带占位符的PreparedStatement,之
后再为其填充数据): 
WHERE (name like ‘Beijing’) AND (address like ‘Beijing’) 
其中WHERE 之后的语句是在dynamic 节点中所定义,因此以dynamic 节点的
prepend 设置("WHERE")作为前缀,而其中的”AND”,实际上是address 属性所对
应的isNotEmpty 节点的prepend 设定,它引领了对应节点中定义的SQL 子句。至于
name 属性对应的isNotEmpty 节点,由于ibatis 会自动判定是否需要追加prepend 
前缀,这里(name like #name#)是WHERE 子句中的第一个条件子句, 无需AND 前
缀,所以自动省略。
判定节点并非仅限于isNotEmpty,ibatis 中提供了丰富的判定定义功能。
判定节点分两类: 

  评论这张
 
阅读(2170)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017