Mybatis动态SQL详解

1、<ResultMap>

作用:该标签自定义某个JavaBean的封装规则;
该标签有2个属性参数:

(1)、type:自定义规则的Java类型
(2)、id:唯一id方便引用

示例:

<resultMap type="com.scorpios.mybatis.bean.Employee" id="MySimpleEmp">
	<id column="id" property="id"/>
	<result column="last_name" property="lastName"/>
	<result column="email" property="email"/>
	<result column="gender" property="gender"/>
</resultMap>

说明
id:定义主键,底层有优化;
column:指定哪一列,指定判定的列名,数据库的字段值
property:指定对应的JavaBean属性;

使用示例:

查询接口如下:public Employee getEmpById(Integer id);对应的SQL的返回结果。

<!-- resultMap:自定义结果集映射规则;  -->
<select id="getEmpById"  resultMap="MySimpleEmp">
	select * from tbl_employee where id=#{id}
</select>

使用场景:

// Employee中有部门属性
public class Employee {
	String id;
	String lastName;
	String gender;
	Department departmen;
	...
}

场景一:查询Employee的同时查询出员工对应的部门信息?

public Employee getEmpAndDept(Integer id)

方式一:联合查询:级联属性封装结果集

<resultMap type="com.scorpios.mybatis.bean.Employee" id="MyDifEmp">
	<id column="id" property="id"/>
	<result column="last_name" property="lastName"/>
	<result column="gender" property="gender"/>
	<result column="did" property="dept.id"/>
	<result column="dept_name" property="dept.departmentName"/>
</resultMap>

方式二:使用association定义关联的单个对象的封装规则,association可以指定联合的JavaBean对象,该标签有2个属性,property,指定哪个属性是联合的对象; javaType:指定这个属性对象的类型[不能省略]

<resultMap type="com.scorpios.mybatis.bean.Employee" id="MyDifEmp2">
	<id column="id" property="id"/>
	<result column="last_name" property="lastName"/>
	<result column="gender" property="gender"/>

	<association property="dept" javaType="com.scorpios.mybatis.bean.Department">
		<id column="did" property="id"/>
		<result column="dept_name" property="departmentName"/>
	</association>
</resultMap>

SQL语句:

<select id="getEmpAndDept" resultMap="MyDifEmp">
	SELECT 
		e.id as id,e.last_name as last_name, e.gender as gender,
		e.d_id as d_id,	d.id as did,d.dept_name as dept_name 
	FROM tbl_employee e,tbl_dept d
	WHERE e.d_id=d.id AND e.id=#{id}
</select>

方式三:使用association进行分步查询:(☆☆☆☆)

第一步、先按照员工id查询员工信息;
第二步、根据查询员工信息中的d_id值去部门表查出部门信息;
第三步、部门设置到员工中;

 <resultMap type="com.scorpios.mybatis.bean.Employee" id="MyEmpByStep">
 	<id column="id" property="id"/>
 	<result column="last_name" property="lastName"/>
 	<result column="email" property="email"/>
 	<result column="gender" property="gender"/>
 	
 	// select:表明当前属性是调用select指定的方法查出的结果
 	// column:指定将哪一列的值传给这个方法
	<association property="dept" 
			select="com.scorpios.mybatis.dao.DepartmentMapper.getDeptById" 
			column="d_id">
	</association>
 </resultMap>

流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性

 <select id="getEmpByIdStep" resultMap="MyEmpByStep">
 	select * from tbl_employee where id=#{id}
 	<if test="_parameter!=null">
 		and 1=1
 	</if>
 </select>

补充:鉴别器 discriminator

鉴别器的作用:mybatis可以使用discriminator来判断某列的值,然后根据某列的值改变来封装行为;

示例要求:
封装Employee:如果查出的是女生,就把部门信息查询出来,否则不查询; 如果是男生,把last_name这一列的值赋值给email

 <resultMap type="com.scorpios.mybatis.bean.Employee" id="MyEmpDis">
 	<id column="id" property="id"/>
 	<result column="last_name" property="lastName"/>
 	<result column="email" property="email"/>
 	<result column="gender" property="gender"/>

 	<discriminator javaType="string" column="gender">
 		<!--女生  resultType:指定封装的结果类型;不能缺少-->
 		<case value="0" resultType="com.scorpios.mybatis.bean.Employee">
 			<association property="dept" 
		 		select="com.scorpios.mybatis.dao.DepartmentMapper.getDeptById" 
		 		column="d_id">
	 		</association>
 		</case>
 		<!--男生 ;如果是男生,把last_name这一列的值赋值给email; -->
 		<case value="1" resultType="com.scorpios.mybatis.bean.Employee">
	 		<id column="id" property="id"/>
		 	<result column="last_name" property="lastName"/>
		 	<result column="last_name" property="email"/>
		 	<result column="gender" property="gender"/>
 		</case>
 	</discriminator>
 </resultMap>

2、动态SQL

(1)、<where>标签和<if>标签的使用

<where>标签作用:可以过滤掉条件语句中的第一个andor关键字。

查询员工,要求,携带了哪个字段查询条件就带上这个字段的值

public List<Employee> getEmpsByConditionIf(Employee employee);

当 id 为 null 时,<where>标签会去掉第一个多余的and

 <select id="getEmpsByConditionIf" resultType="com.scorpios.mybatis.bean.Employee">
 	select * from tbl_employee
 	<where>
	 	<if test="id!=null">
	 		id=#{id}
	 	</if>
	 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
	 		and last_name like #{lastName}
	 	</if>
	 	<if test="email!=null and email.trim()!=&quot;&quot;">
	 		and email=#{email}
	 	</if> 
	 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
	 	<if test="gender==0 or gender==1">
	 	 	and gender=#{gender}
	 	</if>
 	</where>
 </select>

但是如果在写SQL时,把and写在后面时,<where>标签就无能为力了,就像下面这样。

 <select id="getEmpsByConditionIf" resultType="com.scorpios.mybatis.bean.Employee">
 	select * from tbl_employee
 	<where>
	 	<if test="id!=null">
	 		id=#{id} and
	 	</if>
	 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
	 		last_name like #{lastName} and 
	 	</if>
	 	<if test="email!=null and email.trim()!=&quot;&quot;">
	 		email=#{email} and
	 	</if> 
	 	<if test="gender==0 or gender==1">
	 	 	gender=#{gender}
	 	</if>
 	</where>
 </select>
(2)、<trim>标签的使用

作用:去掉拼完之后的字符串前面或后面多出的and或者or,where标签不能解决

参数:只能作用于trim标签体中是整个字符串拼串后的结果。

prefix="":前缀:给拼串后的整个字符串加一个前缀 ;
prefixOverrides="": 前缀覆盖: 去掉整个字符串前面多余的字符;
suffix="":后缀:给拼串后的整个字符串加一个后缀 ;
suffixOverrides="": 后缀覆盖:去掉整个字符串后面多余的字符;

 <select id="getEmpsByConditionTrim" resultType="com.scorpios.mybatis.bean.Employee">
 	
 	select * from tbl_employee
	// 在拼接好的字符串前面加个 where,去掉最后一个and
 	<trim prefix="where" suffixOverrides="and">
 		<if test="id!=null">
	 		id=#{id} and
	 	</if>
	 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
	 		last_name like #{lastName} and
	 	</if>
	 	<if test="email!=null and email.trim()!=&quot;&quot;">
	 		email=#{email} and
	 	</if> 
	 	<if test="gender==0 or gender==1">
	 	 	gender=#{gender}
	 	</if>
	 </trim>
 </select>
(3)、<choose>标签的使用

如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个。

 <select id="getEmpsByConditionChoose" resultType="com.scorpios.mybatis.bean.Employee">
 	select * from tbl_employee 
 	<where>
 		<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>
(4)、<set>标签的使用
 <update id="updateEmp">
 	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} 
(5)、<foreach>标签的使用

该标签有如下属性:
collection:指定要遍历的集合,list类型的参数会特殊处理,封装在map中,map的key就叫list;
item:将当前遍历出的元素赋值给指定的变量;
separator:每个元素之间的分隔符;
open:遍历出所有结果拼接一个开始的字符;
close:遍历出所有结果拼接一个结束的字符;
index:索引。遍历list的时候是:index就是索引,item就是当前值;遍历map的时候index表示的就是map的key,item就是map的值

public List getEmpsByConditionForeach(List ids);

 <select id="getEmpsByConditionForeach" resultType="com.scorpios.mybatis.bean.Employee">
 	select * from tbl_employee where id in 
 	<foreach collection="ids" item="item_id" separator="," open="(" close=")">
 		#{item_id}
 	</foreach>
 </select>

使用<foreach>标签批量保存:

public void addEmps(@Param(“emps”)List emps);

由于MySQL下批量保存:可以foreach遍历;mysql支持values(),(),()语法
方式一:

<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>

方式二:这种方式需要数据库连接属性allowMultiQueries=true;
这种分号分隔多个sql可以用于其他的批量操作(删除,修改)

 	<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>
(6)、<sql>标签的使用

抽取可重用的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>

3、两个内置参数

说明:在sql中获取参数时,不只是方法传递过来的参数可以被用来判断,取值。mybatis中默认还有两个内置参数:
1)、_parameter:代表整个参数

 		单个参数:_parameter就是这个参数(对象就代表传过来的对象)
 		多个参数:参数会被封装为一个map;_parameter就是代表这个map

2)、_databaseId:如果配置了databaseIdProvider标签,databaseId就是代表当前数据库的别名mysql。

©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页