【MyBatis】Mybatis的各种查询功能、特殊SQL、动态SQL、一二级缓存

一、Mybatis的各种查询功能

1.若查询结果只有一条时
(1)可以使用实体类对象接收
(2)也可以使用list和map集合接收;
2.若查询结果有多条
(1)使用实体类类型的的list集合接收
(2)使用map类型的list集合接收
(3)可以在mapper接口的方法上添加@MapKey注解,此时可以将map集合作为值,以某个唯一字段的值作为键,放在同一个map集合中

二、特殊SQL的执行

1.模糊查询

<!--三种方式都可以实现模糊查询,推荐使用方式3-->
<select id="getUserByLike" resultType="com.jd.wds.pojo.User">
    <!--select * from user where username like '%${username}%'-->
    <!--select * from user where username like concat ('%',#{username},'%')-->
    select * from user where username like "%"#{username}"%"
</select>

2.批量删除

<!--批量删除的特殊情况-->
<delete id="deleteMore">
    <!--此处只能使用${}的形式,因为#{}的方式会添加引号,而id的字段名是int-->
    <!--delete from user where id in (#{id})-->
    delete from user where id in (${id})
</delete>

3.动态设置表名

<select id="getUserByTableName" resultType="com.jd.wds.pojo.User">
    <!--此处只能使用${},不能使用#{}-->
    <!--select * from #{tableName}-->
    select * from ${tableName}
</select>

4.字段名和属性名不一致
在这里插入图片描述
在这里插入图片描述
根据不同的规范,创建表时字段选用下划线命名,创建类的属性名选用小驼峰命名,此时就会出现字段名和属性名不完全对应,三种解决方法:

<select id="getAllEmp" resultType="com.jd.wds.pojo.Emp">
    <!--方法1:给对应的字段名设置别名-->
    select eid,emp_name empName,age,sex,email from t_emp
</select>
<!--mybatis的核心配置文件中配置如下,此时sql语句:select * from t_emp-->
<!--方法2:设置全局配置:驼峰命名转下划线命名-->
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--方法3:使用resultmap设置自定义的映射-->
<resultMap id="empResultMap" type="com.jd.wds.pojo.Emp">
    <!--id设置的是主键名,result设置的是非主键名,column是属性名-->
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
</resultMap>
<select id="getAllEmp" resultMap="empResultMap">
    <!--解决字段名和属性名方法1:给对应的字段名设置别名-->
    select * from t_emp
</select>

5.多对一的映射关系
多对一对应对象,一对多对应集合
举个栗子:查询某个员工信息及所在的部门信息(多个员工对应一个部门,典型的多对一)
方法1:resultMap通过级联属性赋值处理

<resultMap id="empAndDeptOne" type="com.jd.wds.pojo.Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
    <!--需要在Emp类中声明dept属性,resultMap通过级联属性赋值-->
    <result property="dept.did" column="did"></result>
    <result property="dept.deptName" column="dept_name"></result>
</resultMap>
<select id="getEmpAndDept" resultMap="empAndDeptOne">
    SELECT * FROM t_emp LEFT JOIN t_dept ON t_emp.did = t_dept.did WHERE t_emp.eid = #{eid}
</select>

方法2:使用association专门处理级联属性赋值

<resultMap id="empAndDeptTwo" type="com.jd.wds.pojo.Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
    <!--需要在Emp类中声明dept属性,使用association专门处理级联属性赋值
    javaType:需要处理的属性的类型;
    property:需要处理的属性名-->
    <association javaType="com.jd.wds.pojo.Dept" property="dept">
        <result property="did" column="did"></result>
        <result property="deptName" column="dept_name"></result>
    </association>
</resultMap>
<select id="getEmpAndDept" resultMap="empAndDeptTwo">
    SELECT * FROM t_emp LEFT JOIN t_dept ON t_emp.did = t_dept.did WHERE t_emp.eid = #{eid}
</select>

方法3:使用分步查询解决

<!--<mapper resource="com/jd/wds/mapper/EmpMapper.xml"/>-->
<!--分步查询员工所对应的部门信息-->
<!--第一步:查询员工信息-->
<resultMap id="EmpAndDeptByStepOne" type="com.jd.wds.pojo.Emp">
    <id property="eid" column="eid"></id>
    <result property="empName" column="emp_name"></result>
    <result property="age" column="age"></result>
    <result property="sex" column="sex"></result>
    <result property="email" column="email"></result>
    <!--association标签中property:属性名,select:第二步的sql查询语句,column:第二步的查询条件-->
    <association property="dept" select="com.jd.wds.mapper.DeptMapper.getEmpAndDeptByStepTwo" column="did"></association>
</resultMap>
<select id="getEmpAndDeptByStepOne" resultMap="EmpAndDeptByStepOne">
    select * from t_emp where eid=#{eid}
</select>
<!--<mapper resource="com/jd/wds/mapper/DeptMapper.xml"/>-->
<!--步骤2:根据查询道德did查询t_dept表中的数据-->
<select id="getEmpAndDeptByStepTwo" resultType="com.jd.wds.pojo.Dept">
    select * from t_dept where did = #{did}
</select>

分步查询的好处:可以实现延迟加载,提高SQL的复用,必须在配置文件中开启才可使用,默认不开启延时加载。
6.一对多的映射关系
多对一对应对象,一对多对应集合
举个栗子:查询某个部门以及部门中员工的信息(一个部门可以有多个员工,典型的一对多)
方法1:使用collection处理一对多的结果映射

<resultMap id="DeptAndEmp" type="com.jd.wds.pojo.Dept">
    <id property="did" column="did"></id>
    <result property="deptName" column="dept_name"></result>
    <!--collection:处理一对多的结果映射,emps:一对多的集合名,ofType:集合emps所对应的集合类型-->
    <collection property="emps" ofType="com.jd.wds.pojo.Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
    </collection>
</resultMap>
<select id="getDeptAndEmp" resultMap="DeptAndEmp">
    select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>

方法2:使用分步查询处理一对多的结果映射

<!--分步查询-->
<!--<mapper resource="com/jd/wds/mapper/DeptMapper.xml"/>-->
<resultMap id="getDeptAndEmpByStep" type="com.jd.wds.pojo.Dept">
    <id property="did" column="did" ></id>
    <result property="deptName" column="dept_name"></result>
    <collection property="emps" select="com.jd.wds.mapper.EmpMapper.getDeptAndEmpByStepTwo" column="did">
    </collection>
</resultMap>
<!--第一步:根据did查询所在的部门信息-->
<select id="getDeptAndEmpByStepOne" resultMap="getDeptAndEmpByStep">
    select * from t_dept where did = #{did}
</select>
<!--<mapper resource="com/jd/wds/mapper/EmpMapper.xml"/>-->
<!--第二步:根据第一步查询结果的did查询所在的员工信息-->
<select id="getDeptAndEmpByStepTwo" resultType="com.jd.wds.pojo.Emp">
    select * from t_emp where did = #{did}
</select>

三、动态SQL

1.< if > 元素
根据标签中test属性所对应的表达式来确定标签中的内容是否要拼接到SQL中。

<!--通过多个条件精确查询某一条数据-->
<select id="getEmpDynamicCondition" resultType="com.jd.wds.pojo.Emp">
    select * from t_emp where 1=1
    <!--test属性的值是属性名-->
    <if test="empName != null and empName !=''">
        and emp_name = #{empName}
    </if>
    <if test="age != null and age !=''">
        and age = #{age}
    </if>
    <if test="sex != null and sex != ''">
        and sex = #{sex}
    </if>
    <if test="email != null and email != ''">
        and email = #{email}
    </if>
</select>

2.< where >元素
当标签中有内容时,将自动生成where关键字,将内容之前的and或or去掉;当标签中没有内容时,where没有任何效果。(and或or在内容之后会报错)

<select id="getEmpDynamicCondition" resultType="com.jd.wds.pojo.Emp">
    select * from t_emp 
    <where>
    <if test="empName != null and empName !=''">
        and emp_name = #{empName}
    </if>
    <if test="age != null and age !=''">
        and age = #{age}
    </if>
    <if test="sex != null and sex != ''">
        and sex = #{sex}
    </if>
    <if test="email != null and email != ''">
        and email = #{email}
    </if>
    </where>
</select>

3.< trim >元素
若标签中有内容:
prefix/suffix:将trim标签中内容前面或后面添加指定内容
suffixoverrides /prefixoverrides : 将trim标签中内容前面或后面去掉指定内容
若标签中没有内容,trim标签没有任何效果。

<select id="getEmpDynamicCondition" resultType="com.jd.wds.pojo.Emp">
    select * from t_emp
    <!--此时在内容之前添加where,条件前面加and|or-->
    <trim prefix="where" prefixOverrides="and|or">
        <if test="empName != null and empName !=''">
            and emp_name = #{empName}
        </if>
        <if test="age != null and age !=''">
            and age = #{age}
        </if>
        <if test="sex != null and sex != ''">
            and sex = #{sex}
        </if>
        <if test="email != null and email != ''">
            and email = #{email}
        </if>
    </trim>
</select>

4.< choose > < when > < otherwise >元素
相当于if,else if,else if,else

<select id="getEmpDynamicCondition" resultType="com.jd.wds.pojo.Emp">
    select * from t_emp where 1=1
    <choose>
        <when test="empName != null and empName !=''">
            and emp_name = #{empName}
        </when>
        <when test="age != null and age !=''">
            and age = #{age}
        </when>
        <when test="sex != null and sex != ''">
            and sex = #{sex}
        </when>
        <when test="email != null and email != ''">
            and email = #{email}
        </when>
        <otherwise>
            did = 1
        </otherwise>
    </choose>
</select>

5.< foreach >元素
foreach用于遍历操作,经常用于批量删除、批量添加等操作。

<!--批量删除操作-->
<delete id="deleteMoreUser">
    <!--方法1:使用in集合的方式-->
    delete from t_emp where eid in
    <foreach collection="eids" open="(" close=")" separator="," item="eid">
        #{eid}
    </foreach>
    <!--方法2:使用or连接条件-->
    delete from t_emp where
    <foreach collection="eids" item="eid" separator="or">
        eid = #{eid}
    </foreach>
</delete>
<!--批量插入操作-->
<insert id="insertMoreUser">
    insert into t_emp values
    <foreach collection="emps" separator="," item="emp">
        (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},#{emp.did})
    </foreach>
</insert>

6.SQL标签
用于设置SQL片段,在需要的位置进行引用即可。

<!--设置sql片段-->
<sql id="columns">eid,emp_name,age,sex,email</sql>
<select id="selectAllUser" resultType="com.jd.wds.pojo.Emp">
	<!--使用sql片段-->
    select <include refid="colums"></include> from t_emp where eid = #{eid}
</select>

四、Mybatis缓存

1.Mybatis的一级缓存

缓存只是针对查询功能,一级缓存是SqlSession级别的,默认开启,下次使用相同的SqlSession查询相同的数据时,直接从缓存中获取,不会从数据库中查询(只执行一次SQL语句,有两个相同的结果)。
一级缓存失效的4种情况:
(1)不同的SqlSession对应的一级缓存
(2)同一个SqlSession对应的查询条件不同
(3)同一个SqlSession两次查询之间执行了任何一次增删改操作
(4)同一个SqlSesion两次查询之间手动清理了缓存

//手动清空缓存
sqlSession.clearCache();

2.Mybatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession的查询结果会被缓存,此后若执行相同的查询语句,结果就会从缓存中获取。
(1)二级缓存开启的条件
① 在核心配置文件中,设置全局配置属性cacheEnabled=“true”

<setting name="cachedEnable" value="true"/>

② 在映射文件中设置标签< cache />
③ 二级缓存必须在SqlSession关闭或提交后生效、
④ 查询的数据所转换的实体类类型必须实现序列化接口
(2)二级缓存失效的条件
两次查询之间执行了任意的增删改操作,会使一二级缓存同时失效。
(3)二级缓存的相关配置
在这里插入图片描述
(4)缓存查询的顺序
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46081857/article/details/123364732