mybatis动态SQL和分页

本文探讨了MyBatis中动态SQL的多种应用,包括if、trim、foreach、choose元素的使用技巧,以及如何处理模糊查询和特殊字符。此外,还介绍了MyBatis分页查询的局限性及PageHelper插件的配置与使用,以实现更高效的大数据量分页。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、动态SQL
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

(1)if

动态 SQL 通常要做的事情是根据条件包含 where 子句的一部分。比如:

SELECT * FROM BLOG WHERE state = ‘ACTIVE’ AND title like #{title} 这条语句提供了一种可选的查找文本功能。如果没有传入“title”,那么所有处于“ACTIVE”状态的BLOG都会返回;反之若传入了“title”,那么就会对“title”一列进行模糊查找并返回 BLOG 结果(细心的读者可能会发现,“title”参数值是可以包含一些掩码或通配符的)。

如果希望通过“title”和“author”两个参数进行可选搜索该怎么办呢?首先,改变语句的名称让它更具实际意义;然后只要加入另一个条件即可。

SELECT * FROM BLOG WHERE state = ‘ACTIVE’ AND title like #{title} AND author_name like #{author.name} (2)trim, where, set


SELECT * FROM BLOG
WHERE

state = #{state}


AND title like #{title}


AND author_name like #{author.name}


如果这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样:

SELECT * FROM BLOG
WHERE
这会导致查询失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
这个查询也会失败,这个问题不能简单地用条件句式来解决,MyBatis 有一个简单的处理,这在 90% 的情况下都会有用。而在不能使用的地方,你可以自定义处理方式来令其正常工作。一处简单的修改就能达到目的:


SELECT * FROM BLOG


state = #{state}


AND title like #{title}


AND author_name like #{author.name}


</select
where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

... prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。

类似的用于动态更新语句的解决方案叫做 set。set 元素可以用于动态包含需要更新的列,而舍去其它的。比如:

update Author username=#{username}, password=#{password}, email=#{email}, bio=#{bio} where id=#{id}

(3)foreach

动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

SELECT * FROM POST P WHERE ID in #{item} oreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及在迭代结果之间放置分隔符。这个元素是很智能的,因此它不会偶然地附加多余的分隔符。

注:你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象传递给 foreach 作为集合参数。当使用可迭代对象或者数组时,index 是当前迭代的次数,item 的值是本次迭代获取的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

(4)choose, when, otherwise

有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。还是上面的例子,但是这次变为提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG:


SELECT * FROM BLOG WHERE state = ‘ACTIVE’


AND title like #{title}


AND author_name like #{author.name}


AND featured = 1



2、模糊查询(3种方式)
(1)参数中直接加入%%

select * from t_mvc_book where bname like #{bname} (2)使用${...}代替#{...}(不建议使用该方式,因为有SQL注入风险) select * from t_mvc_book where bname like '${bname}' 关键:#{...}与${...}区别? 参数类型为字符串,#会在前后加单引号[ ' ],$则直接插入值

(3)SQL字符串拼接CONCAT

select * from t_mvc_book where bname like concat(concat("%","${bname}"),"%") 注: 1) mybatis中使用OGNL表达式传递参数 2) 优先使用#{...} 3) ${...}方式存在SQL注入风险

3、分页查询
为什么要重写mybatis的分页?
因为Mybatis的分页功能很弱,它是基于内存的分页(查出所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没有用的。

(1)导入分页插件

com.github.pagehelper pagehelper 5.1.2 (2)将pagehelper插件配置到mybatis中


(3)在你需要进行分页的Mybatis方法前调用PageHelper.startPage静态方法即可,紧跟在这个方法后的第一个Mybatis查询方法会被进行分页

//设置分页处理
if (null != pageBean && pageBean.isPaginate()) {
PageHelper.startPage(pageBean.getCurPage(), pageBean.getPageRecord());
}
(4)获取分页信息(二种方式)

使用插件后,查询实际返回的是Page,而非List,Page继承了ArrayList,同时还包含分页相关的信息
Page page = (Page)list;
System.out.println(“页码:” + page.getPageNum());
System.out.println(“页大小:” + page.getPageSize());
System.out.println(“总记录:” + page.getTotal());
使用PageInfo
PageInfo pageInfo = new PageInfo(list);
System.out.println(“页码:” + pageInfo.getPageNum());
System.out.println(“页大小:” + pageInfo.getPageSize());
System.out.println(“总记录:” + pageInfo.getTotal());
4、特殊字符处理
使用“>”符号要替换成(>)
使用“<”符号要替换成(<)
使用“&”符号要替换成(&)
使用空格要替换成( )

使用“>”符号或“<”符号或“=”符号时也可使用<![CDATA[ <= ]]> ,如:

select * from t_mvc_book where 1=1 and <![CDATA[price > #{minPrice} and price < #{maxPrice}]]>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值