zoukankan      html  css  js  c++  java
  • 动态SQL (if , choose (when, otherwise) , trim (where, set) , set , foreach)

    为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句。
    最常用的就是:where和if标签
    	
    1.参考官方文档
    	? if:字符判断
    	? choose (when, otherwise):分支选择
    	? trim (where, set):字符串截取;其中where标签封装查询条件,set标签封装修改条件
    	? foreach
    	
    2.if案例:
    	1)在EmployeeMapper接口中添加一个方法:
    		//携带了哪个字段,查询条件就带上哪个字段的值
    		public List<Employee> getEmployeeByConditionIf(Employee employee);
    
        2).如果要写下列的SQL语句,只要是不为空,就作为查询条件,如下所示,这样写实际上是有问题的,所以我们要写成动态SQL语句:
    		<select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee">
    			select *from tbl_employee where id = #{id} and user_name = #{userName} and email = #{email} and gender = #{gender} 
    		</select>
    		
    	3)用if标签改写为动态SQL,如下所示:
    			<select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee">
    				select *from tbl_employee 
    				where 
    				 <!--
    					test:判断表达式(OGNL)
    					OGNL参照PPT或者官方文档。
    						c:if test
    					从参数中取值进行判断
    					遇见特殊符号,应该去写转义字符:参考W3CSchool>>HTML>>ISO8859
    					
    				  -->
    				  <if test="id != null">
    					id = #{id}
    				  </if>
    				  <if test="userName != null && userName !=''">
    					and user_name = #{userName} 
    				  </if>
    				  <if test="email != null and email.trim() != """>
    					and email = #{email}
    				  </if>
    				  <!-- ognl会进行字符串和数字的转换判断;"0"==0,"1"==1 -->
    				  <if test="gender == 0 or gender == 1">
    					and gender = #{gender} 
    				  </if>
    			</select>
    			
        4).测试代码:
    		@Test
    		public void testGetEmployee(){
    			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    			Employee employee = new Employee();
    			employee.setId(1);
    			employee.setUserName("张三丰");
    			employee.setEmail("sunwukong@163.com");
    			employee.setGender(1);
    			 List<Employee> list = mapper.getEmployeeByConditionIf(employee);
    			System.out.println(list);
    		}
    		
      #测试结果没问题
      
      但是仔细来说,上面的sql语句是有问题的,当我们不给动态sql语句传递id值的时候,sql语句的拼装就会有问题!
      解决办法:
        1.给where后面加上1=1,以后的条件都可以使用and xxx了
    	2.mybatis可以使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,
    	  多出来的and或者or去掉!//需要注意:where标签只会去掉第一个多出来的and或者or
    	 
    	3.也就是说使用where标签有时候还是不能解决问题的,那怎么办呢?我们这里可以使用trim标签!
    
    2.trim标签:可以自定义字符串的截取规则
    	  
    			<select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee">
    				select *from tbl_employee
    				<!-- 
    					后面多出的and或者or where标签不能够解决
    				   prefix="":前缀:trim标签体重是整个字符串拼串后的结果。
    							 prefix给拼串后的整个字符串加一个前缀
    				   prefixOverrides="":
    							前缀覆盖:去掉整个字符串前面多余的字符
    				   suffix="":后缀
    					 suffix给拼串后的整个字符串加一个后缀
    				   suffixOverrides="":
    						 后缀覆盖:去掉整个字符串后面多余的字符
    				 --> 
    				<trim prefix="where" suffixOverrides="and">
    				  <if test="id != null">
    					id = #{id} and
    				  </if>
    				  <if test="userName != null && userName !=''">
    					user_name = #{userName} and  
    				  </if>
    				  <if test="email != null and email.trim() != """>
    					email = #{email} and 
    				  </if>
    				  <!-- ognl会进行字符串和数字的转换判断;"0"==0,"1"==1 -->
    				  <if test="gender==0 or gender==1">
    				   gender = #{gender}
    				  </if>		
    				</trim>
    			</select>
    
    3.choose标签:分支选择,类似于Java中的带了break的switch...case
    	choose (when, otherwise):如果带了id,就用id查,如果带了userName就用userName查,只会进入其中一个!
    	
    	案例演示: 
    	   1.在EmployeeMapper接口中添加一个方法:
    			public List<Employee> getEmployeeByConditionChoose(Employee employee);
    	   2.sql映射文件
    			<!-- public List<Employee> getEmployeeByConditionChoose(Employee employee); -->
    			<select id="getEmployeeByConditionChoose" resultType="com.neuedu.entity.Employee">
    				select *from tbl_employee
    				<where>
    					<!-- 如果带了id,就用id查,如果带了userName就用userName查,只会进入其中一个! -->
    					<choose>
    						<when test="id != null">
    							id = #{id}
    						</when>
    						<when test="userName != null">
    							user_name like #{userName}
    						</when>
    						<when test="email != null">
    						   email = #{email}
    						</when>
    						<otherwise>
    							1=1
    						</otherwise>
    					</choose>
    				</where>
    			</select>
    			
    4.trim 中的set标签(where, set):字符串截取;其中where标签封装查询条件,set标签封装修改条件
    	set元素会动态前置set关键字,同时也会消除无关的逗号。
    	
        1).在EmployeeMapper中添加一个更新的方法,如下所示:
    		public void updateEmp(Employee employee);
    	2)在sql映射文件中,填写相应的sql语句,如下所示【set标签可以将字段后面的逗号去掉】:
    		<update id="updateEmp">
    			update tbl_employee 
    			<set>
    				<if test="userName != null">
    					user_name = #{userName},
    				</if>
    				<if test="email != null">
    					email = #{email},
    				</if>
    				<if test="gender != null">
    					gender = #{gender},
    				</if>
    			</set>
    			where id = #{id}
    		</update>
    		
    	测试类代码为:
    		@Test
    		public void testGetEmployee(){
    			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    			Employee employee = new Employee();
    			employee.setId(1);
    			employee.setUserName("哈哈");
    			employee.setEmail("sunwukong@163.com");
    			employee.setGender(1);
    			mapper.updateEmp(employee);
    		}
    	
    	//当然上面的set标签我们也可以使用trim标签来代替,如下所示:
    			<update id="updateEmp">
    				update tbl_employee 
    				<trim prefix="set" suffixOverrides=",">
    					<if test="userName != null">
    						user_name = #{userName},
    					</if>
    					<if test="email != null">
    						email = #{email},
    					</if>
    					<if test="gender != null">
    						gender = #{gender},
    					</if>
    				</trim>
    				where id = #{id}
    			</update>
    	
    	
    5.foreach:遍历元素
    	动态SQL的另一个常用的操作是需要对一个集合进行遍历,通常在构建in条件语句的时候!
    	foreach元素允许指定一个集合,声明集合项和索引变量,并可以指定开闭匹配的字符串以及在迭代之间放置分隔符。
    	
    	案例演示:
    	 1.在EmployeeMapper接口中加入一个方法,如下所示:	
    		   public List<Employee> getEmpsByConditionForeach(@Param("ids") List<Integer> ids);
    	 2.在MyBatis的sql映射文件中写相应的代码:
    			<!-- public List<Employee> getEmpsByConditionForeach(List<Integer> ids); -->
    			<select id="getEmpsByConditionForeach" resultType="com.neuedu.entity.Employee">
    				select * from  tbl_employee where id in
    				<!-- 
    					collection:指定要遍历的集合
    					item:将当前遍历出的元素赋值给指定的变量
    					separator:每个元素之间的分隔符
    					open:遍历出所有记过拼接一个开始的字符
    					close:遍历出所有结果拼接一个结束的字符
    				 -->
    				<foreach collection="ids" open="(" close=")" separator="," item="id">
    					#{id}
    				</foreach>
    			</select>
    			
         3.测试类代码为:
    			@Test
    			public void testGetEmployee(){
    				EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    				List<Integer> asList = Arrays.asList(1,2,3,4);
    				List<Employee> emps = mapper.getEmpsByConditionForeach(asList);
    				for (Employee employee : emps) {
    					System.out.println(employee);
    				}
    			}
    
       foreach标签还可以用于批量保存数据,如下所示:
       
         1.在EmployeeMapper接口类中添加批量插入的方法:
    			public void addEmps(@Param("emps") List<Employee> emps);
    
         2.在EmployeeMapper.xml的sql映射文件中添加响应的语句:
    		
    			<!-- public void addEmps(@Param("emps") List<Employee> emps); -->
    			<!-- MySQL下批量保存:可以foreach遍历,mysql支持values(),(),()语法 -->
    			<insert id="addEmps">
    				INSERT INTO tbl_employee(user_name,gender,email,d_id) VALUES
    				<foreach collection="emps" item="emp" separator=",">
    					(#{emp.userName},#{emp.gender},#{emp.email},#{emp.depart.id})
    				</foreach>
    			</insert>
    	 3.测试代码:
    			@Test
    			public void testGetEmployee(){
    				EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
    				List<Employee> emps = new ArrayList<Employee>();
    				emps.add(new Employee(0, 1, "allen", "allen@163.com", new Department(1)));
    				emps.add(new Employee(0, 0, "tom", "tom@163.com", new Department(2)));
    				emps.add(new Employee(0, 1, "mux", "mux@163.com", new Department(1)));
    				mapper.addEmps(emps);
    			}
    			 
    

      

  • 相关阅读:
    跃迁方法论 Continuous practice
    EPI online zoom session 面试算法基础知识直播分享
    台州 OJ 2648 小希的迷宫
    洛谷 P1074 靶形数独
    洛谷 P1433 DP 状态压缩
    台州 OJ FatMouse and Cheese 深搜 记忆化搜索
    台州 OJ 2676 Tree of Tree 树状 DP
    台州 OJ 2537 Charlie's Change 多重背包 二进制优化 路径记录
    台州 OJ 2378 Tug of War
    台州 OJ 2850 Key Task BFS
  • 原文地址:https://www.cnblogs.com/zhaosong-0102/p/7486865.html
Copyright © 2011-2022 走看看