zoukankan      html  css  js  c++  java
  • 04、MyBatis DynamicSQL(Mybatis动态SQL)

    1.动态SQL简介

      动态 SQL是MyBatis强大特性之一.

      动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似.

      MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作.

     

    2.if

     

    1).实现DynamicSQL

     

    public interface EmployeeMapperDynamicSQL {
    	public List<Employee> getEmpsByCondtionIf(Employee employee);
    }
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- 查询员工:携带指定字段查询条件就带上该字段的值 -->
    	 <!-- public List<Employee> getEmpsByCondtionIf(Employee employee) -->
    	 <select id="getEmpsByCondtionIf" resultType="com.atguigu.mybatis.bean.Employee">
    	 	select * from tbl_employee
    	 	<!-- where:根据条件包含 where 子句 -->
    	 	where
    		 	<!-- test:判断表达式(OGNL) -->
    		 	<!-- OGNL语法参照PPT或者官方文档:http://commons.apache.org/proper/commons-ognl/language-guide.html -->
    		 	<!-- 从参数中取值进行判断,如果遇到特殊符号去写转义字符,查W3C HTML ISO-8859-1 参考手册 -->
    		 	<if test="id!=null">
    		 		id=#{id}
    		 	</if>
    		 	<!-- <if test="lastName!=null and lastName!="""> -->
    		 	<!-- <if test="lastName!=null && lastName!=''"> -->
    		 	<if test="lastName!=null && lastName!=""">
    		 		and last_name like #{lastName}
    		 	</if>
    		 	<if test="email!=null and email.trim()!=""">
    		 		 and email=#{email}
    		 	</if>
    		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
    		 	<if test="gender==0 or gender==1">
    		 		and gender=#{gender}
    		 	</if>
    	 </select>
    </mapper>
    

      

    //			select * from tbl_employee WHERE id=? and last_name like ? and email=?
    //			Employee employee  = new Employee(3, "%e%","atguigu@atguigu.com", null);
    			//select * from tbl_employee WHERE id=? and last_name like ?
    			Employee employee  = new Employee(null, "%e%",null, null);
    			List<Employee> emps = mapper.getEmpsByCondtionIf(employee);
    			for(Employee emp:emps) {
    				System.out.println(emp);
    			}
    

      

    2.choose

      有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用.针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句.

     

    	public List<Employee> getEmpByConditionChoose(Employee employee);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- public List<Employee> getEmpByConditionChoose(Employee employee) -->
    	 <select id="getEmpByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
    	 	select * from tbl_employee 
    	 	<where>
    	 		<!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
    	 		<choose>
    	 				 			<when test="id!=null">
    	 				id=#{id}
    	 			</when>
    	 			<when test="lastName!=null">
    	 				last_name like #{lastName}
    	 			</when>
    	 			<when test="email!=null">
    	 				email = #{email}
    	 			</when>
    	 			<otherwise>
    	 				gender = 0
    	 			</otherwise>
    	 		</choose>
    	 	</where>
    	 </select>
    </mapper>
    

      

    			//测试choose
    			Employee employee  = new Employee(3, "%e%",null, null);
    			List<Employee> list = mapper.getEmpByConditionChoose(employee);
    			for(Employee emp:list) { 
    				System.out.println(emp); 
    			}
    

      

    3.trim

    1).where

     

    	public List<Employee> getEmpsByCondtionTrim(Employee employee);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- public List<Employee> getEmpsByCondtionTrim(Employee employee) -->
    	 <select id="getEmpsByCondtionTrim" resultType="com.atguigu.mybatis.bean.Employee">
    	 	select * from tbl_employee
    	 	<!-- 后面多出的and或者or where标签不能解决,我们使用trim定制where元素功能  -->
    	 	<!-- 自定义字符串的截取规则 -->
    	 	<!-- trim:根据条件包含 where 子句 -->
    	 	<!-- trim标签体中是整个字符串拼串 后的结果 -->
    	 	<!-- 通过自定义 trim 元素来定制 where 元素的功能 -->
    	 	<!-- prefix:前缀;prefix给拼串后的整个字符串加一个前缀  如:where <===> <trim prefix="where"> -->
    	 	<!-- prefixOverrides:前缀覆盖;去掉整个字符串前面多余的字符 -->
    	 	<!-- suffix:后缀;suffix给拼串后的整个字符串加一个后缀 -->
    	 	<!-- suffixOverrides:后缀覆盖;去掉整个字符串后面多余的字符 -->
    	 	<trim prefix="where" suffixOverrides="and">
    		 	<if test="id!=null">
    		 		 id=#{id} and
    		 	</if>
    		 	<if test="lastName!=null && lastName!=""">
    		 		 last_name like #{lastName} and
    		 	</if>
    		 	<if test="email!=null and email.trim()!=""">
    		 		 email=#{email} and
    		 	</if>
    		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
    		 	<if test="gender==0 or gender==1">
    		 		gender=#{gender}
    		 	</if>
    		 </trim>
    	 </select>
    </mapper>
    

      

    	@Test
    	public void testDynamicSql() throws IOException {
    		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    		SqlSession openSession = sqlSessionFactory.openSession();
    		try {
    			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
    //			select * from tbl_employee WHERE id=? and last_name like ? and email=?
    //			Employee employee  = new Employee(3, "%e%","atguigu@atguigu.com", null);
    			//select * from tbl_employee WHERE id=? and last_name like ?
    			Employee employee  = new Employee(3, "%e%",null, null);
    			List<Employee> emps = mapper.getEmpsByCondtionIf(employee);
    			for(Employee emp:emps) {
    				System.out.println(emp);
    			}
    			
    			//查询的时候如果某些条件没带可能sql拼装会有问题
    			//1、给where后面加上1=1,以后的条件都and xxx.
    			//2、mybatis使用where标签来将所有的查询条件包括在内。
    				//mybatis就会将where标签中拼装的sql,多出来的and或者or去掉
    				//where只会去掉第一个多出来的and或者or。
    
    			//测试Trim
    			List<Employee> emps2 = mapper.getEmpsByCondtionTrim(employee);
    			for(Employee emp:emps2) {
    				System.out.println(emp);
    			}
    			
    		} finally {
    			//  : handle finally clause
    			openSession.close();
    		}
    	}
    

      

    2).set

    ①.使用set更新

    	public void  updateEmp(Employee employee);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <update id="updateEmp">
    	 	<!-- set:更新拼串  -->
    	 	<!-- set标签的使用 -->
    	 	update tbl_employee 
     	 	<set>
    	 		<if test="lastName!=null">
    				last_name=#{lastName},
    			</if>
    			<if test="email!=null">
    				email=#{email},
    			</if>
    			<if test="gender!=null">
    				gender=#{gender}
    			</if>
    	 	</set>  
    	 	where id=#{id} 
    	 </update>
    </mapper>
    

      

    			//调试set标签 
    			Employee employee = new Employee(1, "Adminn",null, null); 
    			mapper.updateEmp(employee);
    			openSession.commit();
    

      

    ②.使用trim拼串更新

    	public void  updateEmp(Employee employee);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- public void  updateEmp(Employee employee) -->
    	 <update id="updateEmp">
    	 	<!-- Trim:更新拼串  -->
    		update tbl_employee 
    		<trim prefix="set" suffixOverrides=",">
    			<if test="lastName!=null">
    				last_name=#{lastName},
    			</if>
    			<if test="email!=null">
    				email=#{email},
    			</if>
    			<if test="gender!=null">
    				gender=#{gender}
    			</if>
    		</trim>
    		where id=#{id} 
    	 </update>
    </mapper>
    

      

    			//调试set标签 
    			Employee employee = new Employee(1, "Adminn",null, null); 
    			mapper.updateEmp(employee);
    			openSession.commit();
    

      

    4.foreach

     

      动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候.

     

      当迭代列表、集合等可迭代对象或者数组时;index是当前迭代的次数,item的值是本次迭代获取的元素.

      当使用字典(或者Map.Entry对象的集合)时,index是键,item是值.

    1).MySQL

    (1).遍历记录

    	//查询员工id'在给定集合中的
    	public List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- public List<Employee> getEmpsByConditionForeach(List<Integer> ids) -->
    	 <select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.bean.Employee">
    	 	<!-- collection:指定要遍历的集合;list类型的参数会特殊处理封装在map中,map的key就是list -->
    	 	<!-- item:当前遍历出的元素赋值给指定的变量 -->
    	 	<!-- separator:每个元素之间的分隔符 -->
    	 	<!-- open:遍历出所有结果拼接一个开始的字符 -->
    	 	<!-- close:遍历出所有结果拼接一个结束的字符 -->
    	 	<!-- index:索引;遍历list的时候是index就是索引,item就是当前值;遍历map的时候index表示的就是map的key,item就是map的值 -->
    	 	<!-- #{变量名}:能取出变量的值也就是当前遍历出的元素 -->
    	 	select * from tbl_employee
    	 	<foreach collection="ids" item="item_id" separator="," open="where id in(" close=")">
    	 		#{item_id}
    	 	</foreach>
    	 </select>
    </mapper>
    

      

    			//测试foreach
    			List<Employee> list = mapper.getEmpsByConditionForeach(Arrays.asList(1,2,3,4));
    			for(Employee emp : list) {
    				System.out.println(emp);
    			}
    

      

    (2).批量保存记录1

    	public void addEmps(@Param("emps")List<Employee> emps);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- 批量保存数据 -->
    	 <!-- MySQL下批量保存:可以foreach遍历   mysql支持values(),(),()语法 -->
    	 <!-- public void addEmps(@Param("emps")List<Employee> emps) -->
    	 <!-- insert 方式一 -->
    	 <!-- 推荐使用inert 方式一 -->
     	 <insert id="addEmps">
    	 	insert into tbl_employee(last_name,email,gender,d_id)
    		values
    		<foreach collection="emps" item="emp" separator=",">
    			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
    		</foreach>
    	 </insert> 
    </mapper>
    

      

    			List<Employee> emps = new ArrayList<>();
    			emps.add(new Employee(null, "smith", "smith@atguigu.com", "1",new Department(1)));
    			emps.add(new Employee(null, "allen", "allen@atguigu.com", "0",new Department(1)));
    			mapper.addEmps(emps);
    			openSession.commit();
    

      

    (3).批量保存记录2

    	public void addEmps(@Param("emps")List<Employee> emps);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- insert 方式二 -->
    	 <!-- public void addEmps(@Param("emps")List<Employee> emps) -->
    	 <!-- 这种方式需要数据库连接属性allowMultiQueries=true;
    	 	这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
    	  <insert id="addEmps">
    	 	<foreach collection="emps" item="emp" separator=";">
    	 		insert into tbl_employee(last_name,email,gender,d_id)
    	 		values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
    	 	</foreach>
    	 </insert> 
    </mapper>
    

      

    			List<Employee> emps = new ArrayList<>();
    			emps.add(new Employee(null, "smith", "smith@atguigu.com", "1",new Department(1)));
    			emps.add(new Employee(null, "allen", "allen@atguigu.com", "0",new Department(1)));
    			mapper.addEmps(emps);
    			openSession.commit();
    

      

    2).Oracle

    (1).批量保存1

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <insert id="addEmps" databaseId="oracle">
    	 	<!-- oracle第一种批量方式 -->
    	 	<!-- <foreach collection="emps" item="emp" open="begin" close="end;">
    	 		insert into employees(employee_id,last_name,email) 
    			    values(employees_seq.nextval,#{emp.lastName},#{emp.email});
    	 	</foreach> 
    	 </insert>
    </mapper>
    

    (2).批量保存2

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <insert id="addEmps" databaseId="oracle">
    	 	<!-- oracle第二种批量方式  -->
    	 	insert into employees(
    	 		<!-- 引用外部定义的sql -->
    	 		<include refid="insertColumn">
    	 			<property name="testColomn" value="abc"/>
    	 		</include>
    	 	)
    	 			<foreach collection="emps" item="emp" separator="union"
    	 				open="select employees_seq.nextval,lastName,email from("
    	 				close=")">
    	 				select #{emp.lastName} lastName,#{emp.email} email from dual
    	 			</foreach>
    	 </insert>
    </mapper>
    

      

    5.bind

      bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文.

     

    1).bind

      若在 mybatis 配置文件中配置了 databaseIdProvider , 则可以使用 “_databaseId”变量,这样就可以根据不同的数据库厂商构建特定的语句.

    	public List<Employee> getEmpsTestInnerParameter(Employee employee);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- public List<Employee> getEmpsTestInnerParameter(Employee employee) -->
    	 <!-- mybatis默认还有两个内置参数:_parameter|_databaseId -->
    	 <!-- _parameter:代表整个参数;单个参数:_parameter就是这个参数;多个参数:参数会被封装为一个map,_parameter就是代表这个map -->
    	 <!-- _databaseId:如果配置了databaseIdProvider标签;_databaseId就是代表当前数据库的别名 -->
    	 <select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
    		<!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
    	  		<if test="_databaseId=='mysql'">
    	  			select * from tbl_employee
    	  			<if test="_parameter!=null">
    	  				where last_name like #{lastName}
    	  			</if>
    	  		</if>
    	  		<if test="_databaseId=='oracle'">
    	  			select * from employees
    	  			<if test="_parameter!=null">
    	  				where last_name like #{_parameter.lastName}
    	  			</if>
    	  		</if>
    	  </select>
    </mapper>
    

      

    	@Test
    	public void testInnerParam() throws IOException{
    		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    		SqlSession openSession = sqlSessionFactory.openSession();
    		try{
    			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
    			Employee employee2 = new Employee();
    			employee2.setLastName("%e%");
    			List<Employee> list = mapper.getEmpsTestInnerParameter(employee2);
    			for (Employee employee : list) {
    				System.out.println(employee);
    			}
    		}finally{
    			openSession.close();
    		}
    	}
    

      

    2).SQL片段

    	public void addEmps(@Param("emps")List<Employee> emps);
    

      

    <mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
    	 <!-- insert 方式三 -->
    	<insert id="addEmps">
    		insert into tbl_employee(
    			<include refid="insertColumn"></include>
    	 	) 
    		values
    		<foreach collection="emps" item="emp" separator=",">
    			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
    		</foreach>
    	</insert>
    	<!-- 抽取可重用的sql片段;方便后面引用  -->
    	<!-- 1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用 -->
    	<!-- 2、include来引用已经抽取的sql -->
    	<!-- 3、include还可以自定义一些property,sql标签内部就能使用自定义的属性 -->
    	<!-- include-property:取值的正确方式${prop} #{不能使用这种方式} -->  			
    	<sql id="insertColumn">
    		<if test="_databaseId=='oracle'">
    			employee_id,last_name,email
    		</if>
    		<if test="_databaseId=='mysql'">
    			last_name,email,gender,d_id
    		</if>
    	</sql>
    </mapper>
    

      

    	@Test
    	public void testBatchSave() throws IOException {
    		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    		SqlSession openSession = sqlSessionFactory.openSession();
    		try {
    			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
    			List<Employee> emps = new ArrayList<>();
    			emps.add(new Employee(null, "smith", "smith@atguigu.com", "1",new Department(1)));
    			emps.add(new Employee(null, "allen", "allen@atguigu.com", "0",new Department(1)));
    			mapper.addEmps(emps);
    			openSession.commit();
    		}finally {
    			openSession.close();
    		}
    	}
    

    6.OGNL

     

    参考文档:http://commons.apache.org/proper/commons-ognl/language-guide.html

    https://mybatis.org/mybatis-3/zh/dynamic-sql.html

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
  • 原文地址:https://www.cnblogs.com/HOsystem/p/13150179.html
Copyright © 2011-2022 走看看