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);
    			}
    			 
    

      

  • 相关阅读:
    数据库连接池
    批量插入数据库数据,有则更新,无则追加
    初识gensim
    Python pip install之SSL异常处理
    使用Fiddler和夜神浏览器对搜狐推荐新闻的抓取
    使用Fiddler抓取夜神模拟器上的包
    教你如何用GatherProxy,自己找SOCKS代理
    logging.Formatter 日期格式
    由于找不到MSVCR120.dll,无法继续执行代码.重新安装程序可能会解决此问题。
    beautifulsoup的简单使用
  • 原文地址:https://www.cnblogs.com/zhaosong-0102/p/7486865.html
Copyright © 2011-2022 走看看