MyBatis 的核心就是能够对 SQL 语句进行灵活的操作,甚至还可以通过表达式进行判断,对 SQL 语句进行灵活 的拼装,组成最终的想要执行的 SQL,这就是动态 SQL 的含义。 例如,在进行复杂查询时,查询条件可能是多个,也可能是一个,也就是说,查询条件不确定。需要根据查询条 件,来确定最终执行的 SQL 语句。
使用 mybatis 的动态 SQL 时,需要标签元素的支持,最常用的为 where 元素和 if 元素
<select id="queryUserByItemName" parameterType="userVo" resultType="user"> select * from user join item on user.user_id=item.user_id <where> <if test="item!=null and item.name!=null and item.name!=''"> and item.name=#{item.name} </if> <if test="cname!=null and cname!=''"> and user.cname like #{cname} </if> </where> </select>
程序解析:配置动态 SQL 时,要用 where 标签转换成 where 关键字,不要把 where 关键字写死在 SQL 中,因 为如果 SQL 中的条件判断都不成立,就没有后面的过滤条件,如果 where 关键字写死在 SQL 语句中反而出错。而使 用 where 标签,由 MyBatis 框架在解析时判断是否需要在 SQL 中加入 where 关键字。 if 标签中的判断,首先判断是否不为 null,然后再判断是否不为空,判断空时使用两个单引号,并且单引号中间 不能有空格。过滤条件的拼接关键字 and、or 等一定要写死在 SQL 中,MyBatis 框架不会为 SQL 拼接 and、or 等 关键字,但是如果 where 关键字后出现了 and 或者 or 关键字,MyBatis 反而会去掉这个关键字。例如上面程序中, 第一个 if 判断成立,SQL 语句会变成 where and item.name=? ,此时 MyBatis 就会去掉这个关键字
在 mapper.xml 配置文件中,如果存在大量的复杂查询,而且查询条件相同,那么则可以把查询条件抽取成一个 SQL 片段,在其他 SQL中引用该片段即可。
<!-- 定义 SQL 片段 --> <sql id="userQuery"> <where> <if test="item!=null and item.name!=null and item.name!=''"> and item.name=#{item.name} </if> <if test="cname!=null and cname!=''"> user.cname like #{cname} </if> </where> </sql> <!-- 根据商品名称查询,引用 SQL 片段 --> <select id="queryUserByItemName" parameterType="userVo" resultType="user"> select * from user join item on user.user_id=item.user_id <include refid="userQuery" /> </select>
程序解析:通过 SQL 片段的定义,不仅可以减少 mapper.xml 配置文件的书写,而且方便程序人员的开发。
在进行复杂 SQL 查询时,往往会遇到这样一种情况,对于某个列的值,好几个值都符合条件,使用 SQL 书写格 式如下:
where column='value1' or column='value2' or column='value3'
执行此 SQL 时传入的参数就需要是个集合,在 MyBatis 中,对于这种情况的处理,使用 foreach 元素解决。 foreach 标签用于遍历传入的集合,属性如下:
public List<User> queryUserByIds(List<Integer> idList);
<select id="queryUserByIds" parameterType="list" resultMap="userMap"> select * from user <where> <foreach collection="list" item="value" separator=" or "> user_id=#{value} </foreach> </where> </select>
@Test public void testQueryUserByIds() throws Exception{ List<Integer> idList = new ArrayList<>(); idList.add(13); idList.add(14); idList.add(15); UserMapper mapper = session.getMapper(UserMapper.class); List<User> userList = mapper.queryUserByIds(idList); for (User userObj : userList) { System.out.println(userObj.getCname()); } }
程序解析:如果 List 集合中不存在元素,上面 mapper.xml 配置文件中定义的 foreach 则不会执行,最终执行 的 SQL 为:select * from user。对上面的 SQL 进行更改为另一种格式,使用 in的方式 如下图所示:
<select id="queryUserByIds" parameterType="list" resultMap="userMap"> select * from user <where> <foreach collection="list" item="value" open="user_id in (" separator="," close=")"> #{value} </foreach> </where> </select>
测试程序同上。