多条件查询
我们经常会遇到如上图所示的多条件查询,将多条件查询的结果展示在下方的数据列表中。而我们做这个功能需要分析最终的SQL语句应该是什么样,思考两个问题
- 条件表达式
- 如何连接
条件字段 企业名称 和 品牌名称 需要进行模糊查询,所以条件应该是:
简单的分析后,我们来看功能实现的步骤:
- 编写接口方法
参数:所有查询条件
结果:List<Brand>
- 在映射配置文件中编写SQL语句
- 编写测试方法并执行
编写接口方法
在 BrandMapper 接口中定义多条件查询的方法。
而该功能有三个参数,我们就需要考虑定义接口时,参数应该如何定义。Mybatis针对多参数有多种实现
使用 @Param("参数名称") 标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);
将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和实体类属性名保持一致。
List<Brand> selectByCondition(Brand brand);
将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和map集合中键的名称一致。
List<Brand> selectByCondition(Map map);
编写SQL语句
在 BrandMapper.xml 映射配置文件中编写 statement,使用 resultMap 而不是使用 resultType
<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand where status = #{status} and company_name like #{companyName} and brand_name like #{brandName} </select>
编写测试方法
在 test/java 下的 com.itheima.mapper 包下的 MybatisTest类中 定义测试方法
@Test public void testSelectByCondition() throws IOException { //接收参数 int status = 1; String companyName = "华为"; String brandName = "华为"; // 处理参数 companyName = "%" + companyName + "%"; brandName = "%" + brandName + "%"; //1. 获取SqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2. 获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //3. 获取Mapper接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 //方式一 :接口方法参数使用 @Param 方式调用的方法 //List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName); //方式二 :接口方法参数是 实体类对象 方式调用的方法 //封装对象 /* Brand brand = new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName);*/ //List<Brand> brands = brandMapper.selectByCondition(brand); //方式三 :接口方法参数是 map集合对象 方式调用的方法 Map map = new HashMap(); map.put("status" , status); map.put("companyName", companyName); map.put("brandName" , brandName); List<Brand> brands = brandMapper.selectByCondition(map); System.out.println(brands); //5. 释放资源 sqlSession.close(); }
动态SQL
上述功能实现存在很大的问题。用户在输入条件时,肯定不会所有的条件都填写,这个时候我们的SQL语句就不能那样写的
例如用户只输入 当前状态 时,SQL语句就是
select * from tb_brand where status = #{status}
而用户如果只输入企业名称时,SQL语句就是
select * from tb_brand where company_name like #{companName}
而用户如果输入了 当前状态 和 企业名称 时,SQL语句又不一样
select * from tb_brand where status = #{status} and company_name like #{companName}
针对上述的需要,Mybatis对动态SQL有很强大的支撑:
if
choose (when, otherwise)
trim (where, set)
foreach
我们先学习 if 标签和 where 标签:
if 标签:条件判断
test 属性:逻辑表达式
<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand where <if test="status != null"> and status = #{status} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> </select>
如上的这种SQL语句就会根据传递的参数值进行动态的拼接。如果此时status和companyName有值那么就会值拼接这两个条件。
执行结果如下:
但是它也存在问题,如果此时给的参数值是
Map map = new HashMap(); // map.put("status" , status); map.put("companyName", companyName); map.put("brandName" , brandName);
拼接的SQL语句就变成了
select * from tb_brand where and company_name like ? and brand_name like ?
而上面的语句中 where 关键后直接跟 and 关键字,这就是一条错误的SQL语句。这个就可以使用 where 标签解决
where 标签
作用:
替换where关键字
会动态的去掉第一个条件前的 and
如果所有的参数没有值则不加where关键字
<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand <where> <if test="status != null"> and status = #{status} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> </where> </select>
注意:需要给每个条件前都加上 and 关键字。