使用动态SQL完成多条件查询

动态SQl是MyBatis的一个强大的特性,在使用JDBC操作数据时,如果查询条件特别多,将条件串联成SQL字符串是一件痛苦的事情,通常的解决方法是写很多的if-else条件语句对字符串进行拼接, 并确保不能忘了空格在字段的最后省略都好,MyBatis使用一种很强大的动态SQL语言来改善这种情形.动态SQL基于OGNL的表达式,可使我们方便地在SQL语句中实现某些逻辑.用于实现动态SQL的元素如下.

  • if:利用if实现简单的条件选择.
  • choose(when,otherwise):相当于Java中的switch语句,通常与when和otherwise搭配.
  • when:简化SQL语句中的where条件判断
  • set:解决动态更新语句
  • 可以灵活地去除多余的关键字
  • foreach:迭代一个集合,通常用于in条件;

1使用if+where实现多条件查询

(1)if

在该实例中,采用的是封装User对象入参,进行查询.

/**
	 * 查询用户列表
	 * @param userName
	 * @param userRoId
	 * @return
	 */
	public List<User> getUsersList(@Param("userName")String userName,@Param("userRole")Integer userRoId);
}

在上述代码中使用了@Param注解,并将参数roleId重名名为userRole,故UserMapper.xml的代码如下:

<!-- 查询用户列表 -->
  <select id="getUserList" resultMap="userList">
  		select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id
  		and u.userName like CONCAT('%',#{userName},'%')
			and u.userRole =#{userRole}
  </select>
  <!-- userList映射 -->
  <resultMap type="cn.smbms.pojo.User" id="userList">
		<result property="id" column="id"/>
		<result property="userCode" column="userCode"/>
		<result property="userName" column="userName"/>
		<result property="phone" column="phone"/>
		<result property="birthday" column="birthday"/>
		<result property="gender" column="gender"/>
		<result property="userRole" column="userRole"/>
		<result property="userRoleName" column="userRoleName"/>
	</resultMap>

完成修改后运行调试类,首先测试2个条件给均给出的情况测试方法,部分代码如下

		int roleId=3;
		String userName="孙";
		List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
		for (User user : users) {
			System.out.println("userName: "+user.getUserName()+" userRole: "+user.getUserRoleName());
		}

运行效果如下:


然后模拟用户没有输入所有条件的情况下,如传入的用户角色roleId参数为空,即只按用户名称进行模糊查询,测试方法如下

@Test
	public  void getUserList() {
		// TODO Auto-generated method stub
		SqlSession sqlSession=MyBatisUtil.createSqlsession();
		int roleId=3;
		String userName=null;
		List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
		for (User user : users) {
			System.out.println("userName: "+user.getUserName()+" userRole: "+user.getUserRoleName());
		}
	}

运行效果如下:
在这里插入图片描述
通过该运行效果可以发现,查询列表为空,根据业务需求,用户并不会完整地输入所有的查询条件,因此用于这只用情况使用动态SQL的if元素来实现,具体实现代码如下:

 <!-- 查询用户列表 -->
<select id="getUserList" resultMap="userList">
		SELECT u.*,r.roleName FROM smbms_user u,smbms_role r WHERE u.userrole=r.id
		<if test="userRole!=null">
			and u.userRole=#{userRole}
		</if>
		<if test="userName!=null and userName!=''">
			and u.userName like CONCAT('%',#{userName},'%')
		</if>
	</select>
  <!-- userList映射 -->
  <resultMap type="cn.smbms.pojo.User" id="userList">
		<result property="id" column="id"/>
		<result property="userCode" column="userCode"/>
		<result property="userName" column="userName"/>
		<result property="phone" column="phone"/>
		<result property="birthday" column="birthday"/>
		<result property="gender" column="gender"/>
		<result property="userRole" column="userRole"/>
		<result property="userRoleName" column="roleName"/>
	</resultMap>

运行效果如下:
在这里插入图片描述
在这里插入图片描述

(2)where

改造上面的示例,需求为:根据用户名称(模糊查询)和角色id查询用户列表,但是用户列表不需要显示角色名称.修改示例代码,只需要将UserMapper.xml中的getUserList的select的返回值类型改为resultType,并修改SQL,代码如下:

// TODO Auto-generated method stub
			SqlSession sqlSession=MyBatisUtil.createSqlsession();
			int roleId=3;
			String userName=null;
			List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
			System.out.println("userSize: "+users.size());
			for (User user : users) {
				System.out.println("userName: "+user.getUserName()+" userRole: "+user.getUserRoleName());
			}
		}

然后进行测试,测试方法代码片段如下:

			int roleId=3;
			String userName=null;
			List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
			System.out.println("userSize: "+users.size());
			for (User user : users) {
				System.out.println("userName: "+user.getUserName()+" userRole: "+user.getUserRoleName());
			}
		}

运行效果如下:
在这里插入图片描述
通过运行结果,发现后台报错,具体错误为SQL语句错误即while后面多了一个and;
where元素主要是用来简化SQL语句中的where条件判断,并能智能的处理and和or,不必担心多余关键字导致的语法错误.下面通过一个示例演示,修改UserMapper.xml代码如下:

<select id="getUserList" resultType="User">
		SELECT * FROM smbms_user
		<where>
			<if test="userName!=null and userName!=''">
				userName like CONCAT('%',#{userName},'%')
			</if>
			<if test="userRole!=null">
				and userRole=#{userRole}
			</if>
		</where>
	</select>

通过上述代码,where元素标签会自动识别其标签内是否有返回值,若有,就插入一个where,此外,若该便签的内容是以and或者or开头的,会自动剔除.下面根据以上两种出错情况分别进行运行调试;
> 第一种情况,参数userName传入空字符串(或者null),参数roleId给定值,测试方法代码片段如下:

// TODO Auto-generated method stub
			SqlSession sqlSession=MyBatisUtil.createSqlsession();
			int roleId=3;
			String userName=null;
			List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
			System.out.println("userSize: "+users.size());
			for (User user : users) {
				System.out.println("userName: "+user.getUserName()+" userRole: "+user.getUserRoleName());
			}
		}

运行效果如下:
在这里插入图片描述
通过上图可知控制台输出的SQL语句根据传递的参数进行了正确拼接,where子句里自动剔除了"and"
>第二种情况:两个参数传入的值均为空,测试方法代码片段如下:

			Integer roleId=null;
			String userName="";
			List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
			System.out.println("userSize: "+users.size());
			for (User user : users) {
				System.out.println("userName: "+user.getUserName());
			}

运行效果如下:
在这里插入图片描述
通过上图可知运行正确如下,控制台输出的日志SQL语句同样传递的参数进行了正确拼接,由于此种情况下没有参数所以自动去除where;
其实这些方法都很麻烦,下面介绍一个简单的方法
>重点就是在userMapper.xml文件里面修改里面的代码
在这里插入图片描述
在sql语句中加入where 1 =1 ,后面直接用if标签判断值是否为空,这样就能避免where标签不能去除,已经多余的and无法剔除;
同样的测试下代码:

			//userName为空
			Integer roleId=3;
			String userName="";
			List<User> users=sqlSession.getMapper(UserMapper.class).getUserList(userName,roleId);
			System.out.println("userSize: "+users.size());
			for (User user : users) {
				System.out.println("userName: "+user.getUserName());
			}

测试结果如下:
在这里插入图片描述
测试结果可知去除了roleId的那段代码;
接下来测试当userName为空的时候,测试代码如下:
在这里插入图片描述
在这里插入图片描述
由上面的日志文件可知,自动剔除了userName的那段代码;
看到这个时候不要生气,不要时候为啥不直接说这个,简单的方法,学习从来没有简单方法,要一步一步走过来,也只有坚持到最后的人,才能看到这个方法

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值