1、背景:
线上经常出现因为研发代码编写不规范,sql语句全表查询,数据过多,硬生生把内存塞爆不断GC,整个服务宕掉的情况。
引发这种场景的原因之一,归咎在使用mybatis编写sql语句时使用了万能查询语句。where 1=1之后,拼接的if条件都不符合条件。如下:
如果下面sql语句中,if条件都匹配不上,最后会执行 select * from retailer where 1=1
1 <!--sql片段--> 2 <sql id="query_retailer_where"> 3 <if test="name!=null">and name like '%${name}%'</if> 4 <if test="address!=null">and address like '%${address}%'</if> 5 <if test="status!=null">and status like '%${status}%'</if> 6 <if test="telphone!=null">and telphone = #{telphone}</if> 7 <if test="createtime!=null"> 8 and createtime = DATE_FORMAT(#{createtime},'%Y-%m-%d %H:%i:%S') 9 </if> 10 <if test="starttime != null"> <![CDATA[ and createtime >= to_date(#{starttime},'yyyy-MM-dd HH:mm:ss')]]></if> 11 <if test="endtime != null"> <![CDATA[ and createtime <= to_date(#{endtime},'yyyy-MM-dd HH:mm:ss')]]></if> 12 </sql> 13 14 <!--查询--> 15 <select id="find" resultMap="resultMap" parameterType="java.util.Map"> 16 select * from retailer 17 where 1=1 18 <include refid="query_retailer_where"></include> 19 <if test="startPage != null and pageSize !=null"> 20 order by createtime desc 21 -- LIMIT #{startPage},#{pageSize} 22 </if> 23 </select>
这类场景的解决办法,
一种是使用<choose></choose>,如果匹配不到就查询不到,或查询个默认范围。
<where> <choose> <when> </when> <otherwise> AND 1=0 </otherwise>
</choose>
</where>
另外一种就是使用分页查询,引入Limit,限制查询出的数据条数。
2、使用思路:
<!--查询--> <select id="find" resultMap="resultMap" parameterType="java.util.Map"> select * from retailer where 1=1 <include refid="query_retailer_where"></include> <if test="startPage != null and pageSize !=null"> order by createtime desc LIMIT #{startPage},#{pageSize} </if> </select>
由底向上的思路,从limit的使用,来考虑一下传值的逻辑。
limit的语法是,select * from table where ... limit start,size;
start:从第几条记录开始。
size : 读取几条记录。
首先需要知道,从第几条[下标]开始读,要往后读取多少条。
即分页显示的话,需要传给sql语句两个参数,某一页面中第一条在表中的下标,以及页面中数据的条数。
size好说,默认指定一个,或者从前台输入后取一个。
start下标,
一种方式是,前端js计算完,直接传值过来。不涉及sql语句的计算。
另一种方式是,前端传过来要跳转到的页码,后台sql中加入(pageNum-1)*size的计算,即为对应页面的start下标值。
3、实现:
以第一种为例。
1)编写分页查询的PageEntity类,首次查询列表,需要给定个默认值。
/** * 分页类,包含三个属性 * 开始页面、起始数据位置、每页要取的数据 */ public class PageEntity { //当前页 private Integer currentPage; //起始页 private Integer startPage; //页面的数据大小 private Integer pageSize; public Integer getCurrentPage() { if(currentPage==null){ currentPage = 1; } return currentPage; } public void setCurrentPage(Integer currentPage) { this.currentPage = currentPage; } public Integer getStartPage() { if (startPage==null){ startPage=0; } return startPage; } public void setStartPage(Integer startPage) { this.startPage = startPage; } public Integer getPageSize() { if (pageSize==null){ pageSize=5; } return pageSize; } public void setPageSize(Integer pageSize) { this.pageSize = pageSize; } }