Mybatis 映射文件的 SQL 深入
参考的官方文档,描述如下:
1. 动态 SQL 之 标签
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
UserMapper接口中加如下方法
/***
* 根据QueryVo查询 * @param queryVo * @return */ List<User> findByVo(QueryVo queryVo);
UserMapper.xml 代码如下:
<!--findByVo--> <select id="findByVo" parameterType="QueryVo" resultType="User"> SELECT id,username,birthday,sex,address FROM USER WHERE 1=1 <!--QueryVo中封装了user属性,而条件要的是user的id属性,注意这种写法--> <if test="user.id!=null"> AND id=#{user.id} </if> <!--QueryVo中封装了user属性,而条件要的是user的username属性,注意这种写法--> <if test="user.username!=null and user.username!=''"> AND username=#{user.username} </if> </select>
注意: 标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
另外要注意 where 1=1 的作用~!
测试代码:
@Test
public void testFindByVo(){ //封装User数据 User user = new User(); //user.setUsername("老王"); user.setId(46); //封装QueryVo QueryVo queryVo = new QueryVo(); queryVo.setUser(user); /*** * 根据QueryVo查询 */ List<User> users = userMapper.findByVo(queryVo); for (User u : users) { System.out.println(u); } }
为了简化上面 where 1=1 的条件拼装,我们可以采用 标签来简化开发。
修改 UserMapper.xml 映射文件如下:
<!--findByVo--> <select id="findByVo" parameterType="QueryVo" resultType="User"> SELECT id,username,birthday,sex,address FROM USER <where> <!--QueryVo中封装了user属性,而条件要的是user的id属性,注意这种写法--> <if test="user.id!=null"> AND id=#{user.id} </if> <!--QueryVo中封装了user属性,而条件要的是user的username属性,注意这种写法--> <if test="user.username!=null and user.username!=''"> AND username=#{user.username} </if> </where> </select>
可以自动处理第一个 and。
- 需求
传入多个 id 查询用户信息,用下边两个 sql 实现: SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16) SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。这样我们将如何进行参数的传递?
在 QueryVo 中加入一个 List 集合用于封装参数
在UserMapper接口中加入如下方法
/** * 根据ID集合查询 * @param queryVo * @return */ List<User> findByRang(QueryVo queryVo);
在UserMapper.xml中加入findByRang方法
<!--findByRang-->
<select id="findByRang" parameterType="QueryVo" resultType="User"> SELECT id,username,birthday,sex,address FROM USER <where> <if test="ids!=null and ids.size>0"> <foreach collection="ids" item="id" close=")" open="AND id IN (" separator=","> #{id} </foreach> </if> </where> </select>
SQL 语句: select 字段 from user where id in (?)
< foreach>标签用于遍历集合,它的属性:
- collection:代表要遍历的集合元素,注意编写时不要写#{}
- open:代表语句的开始部分
- close:代表结束部分
- item:代表遍历集合的每个元素,生成的变量名
- sperator:代表分隔符
在测试中增加测试方法
/*** * 根据findByRang查询 */ @Test public void testFindByRang(){ //封装QueryVo QueryVo queryVo = new QueryVo(); List<Integer> ids = new ArrayList<Integer>(); ids.add(41); ids.add(45); queryVo.setIds(ids); /*** * 根据findByRang查询 */ List<User> users = userMapper.findByRang(queryVo); for (User u : users) { System.out.println(u); } }
2. Mybatis 中简化编写的 SQL 片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。
我们先到 UserMapper.xml 文件中使用 标签,定义出公共部分,如下:
<!--定义SQL片段--> <sql id="selectUserTable"> SELECT id,username,birthday,sex,address FROM USER </sql>
然后在 UserMapper.xml 文件中用 标签再引用上面的 id。
<!--findByRang--> <select id="findByRang" parameterType="QueryVo" resultType="User"> <include refid="selectUserTable" /> <where> <if test="ids!=null and ids.size>0"> <foreach collection="ids" item="id" close=")" open="AND id IN (" separator=","> #{id} </foreach> </if> </where> </select>
其中 标签的 refid 属性的值就是 标签定义 id 的取值。
注意:如果引用其它 mapper.xml 的 sql 片段,则在引用时需要加上 namespace,如下:
<include refid="namespace.sql 片段"/>