本文内容基于之前的博客Spring Boot实战小技巧(三):Spring Boot + Mybatis-Plus Mybatis-Plus自带简单的数据库增删改查函数,但在实际应用中,经常会遇到实现复杂查询或循环添加等操作的需求,需要使用动态sql语句。我们可以在mapper文件,用注解的方式进行动态sql语句的编写,动态sql语句需要添加 <script> </scrpit>
标签 。
1 动态查询条件
当sql语句的查询条件需要满足某种条件才能生效时,我们可以使用if标签和choose标签来实现sql查询条件的动态变化,if标签是与(and)的关系,choose是或(or)的关系。
使用if标签时,只有test条件成立,才会动态添加sql语句。test中的条件需要用\"
括起来。大于号和小于号属于特殊字符,使用时需要用>
和<
代替,示例如下:
@Select({
"<script>",
"select count(*) from tb_person",
"<where>",
"<if test=\"null != param.startTime\">",
"and create_time>=#{param.startTime}",
"</if>",
"<if test=\"null != param.endTime\">",
"and create_time<=#{param.endTime}",
"</if>",
"</where>",
"</script>"
})
int countPersons(@Param("param") ParamEntity param);
choose标签是按顺序判断其内部when标签中的test条件是否成立,如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行otherwise中的sql。类似于Java的switch语句,choose为switch,when为case,otherwise则为default。示例如下:
@Select({
"<script>",
"select * from tb_person",
"<where>",
"<choose>",
"<when test=\"0 == param.state\">",
"and key_person=#{param.state} and id!='1'",
"</when>",
"<when test=\"1 == param.state\">",
"and (key_person=#{param.state} or id='1')",
"</when>",
"<when test=\"5 == param.state\">",
"and id='1'",
"</when>",
"<otherwise>",
"</otherwise>",
"</choose>",
"<if test=\"null != param.name and '' != param.name\">",
"and xm like #{param.name}",
"</if>",
"<if test=\"null != param.idCard and '' != param.idCard\">",
"and sfzh like #{param.idCard}",
"</if>",
"<if test=\"null != param.startTime\">",
"and create_time>=#{param.startTime}",
"</if>",
"<if test=\"null != param.endTime\">",
"and create_time<=#{param.endTime}",
"</if>",
"</where>",
"order by create_time desc limit #{offset},#{count}",
"</script>"
})
List<Person> listPersons(@Param("param") ParamEntity param, @Param("offset") int offset, @Param("count") int count);
为安全考虑,通常会使用where标签将if和choose标签封装起来,避免第一个条件成立时sql语句会多出一个and或or。但如果有固定条件在前,即可省略where标签。示例如下:
@Select({
"<script>",
"select count(*) from tb_person where is_delete=0",
"<if test=\"null != param.startTime\">",
"and create_time>=#{param.startTime}",
"</if>",
"<if test=\"null != param.endTime\">",
"and create_time<=#{param.endTime}",
"</if>",
"</script>"
})
int countPersons(@Param("param") ParamEntity param);
2 循环操作
当需要实现根据某条件进行循环查询或写入操作时,我们可以使用foreach标签。
循环写入示例如下:
@Insert({
"<script>",
"REPLACE INTO tb_person (uuid, id, name, dept_name, picture, age, sex, adress, create_time, is_upload, is_delete) VALUES",
"<foreach collection='list' index='index' item='item' separator=','>",
"(#{item.uuid}, #{item.id}, #{item.name}, #{item.deptName}, #{item.picture}, #{item.age}, #{item.sex}, #{item.address}, #{item.createTime}, #{item.isUpload}, #{item.isDelete})",
"</foreach>",
"</script>"
})
int replaceList(@Param("list") List<Person> list);
replace into跟insert功能类似,不同点在于replace into首先尝试插入数据到表中,如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据;否则,直接插入新数据。
需要注意的是,插入数据的表必须有主键或者是唯一索引,否则replace into会直接插入数据,导致表中出现重复的数据。
查询时循环匹配示例如下:
@Select({
"<script>",
"select task_id from tb_task",
"where id in",
"<foreach collection='list' index='index' item='item' separator=','>",
"#{item.id}",
"</foreach> )",
"and is_delete=0",
"</script>"
})
List<String> getTasks(@Param("list") List<Task> list);