MyBatis高级

学习目标

1. 动态SQL
2. 关联查询
3. 延迟加载
4. 缓存机制

1.动态SQL

1.1为什么要使用动态SQL

如果我们要实现多条件的查询,该怎么设计?

一般情况下,需要使用SQL拼接的方式实现
String sql = "select * from phone where 1 = 1 ";
if(a != null)
{
  sql += " and a = " + a;
}
if(b != null)
{
  sql += " and b = " + b;
}

缺点:

  1. Java代码中出现大量if,可读性和维护性比较差
  2. 拼接字符串容易出现错误

1.2动态SQL简介
 MyBatis的一个重要特性就是动态SQL,能通过条件动态生成SQL语句
 动态SQL包含几种标签:

1.sql

2.if

3.where

4.set

5.trim

6.foreach

1.2.1 sql标签

可以通过sql标签提高sql代码的复用性
定义代码片段

 <sql id="sql_select">
        select id,name,age,address,deptId
    </sql>

 <!--查询所有-->
    <select id="findAll" resultType="Employee">
        <include refid="sql_select"></include> from employee
    </select>

1.2.2 if标签

 进行条件判断,判断成功会把if内部SQL拼接到外部SQL中,否则不拼接

<if test="条件">
	SQL语句
</if>

1.2.3 where标签

 用于配置条件,会去掉多余的where、and、or关键词

<!--多条件查询一条信息-->
    <select id="findById" resultType="Employee">
        <include refid="sql_select"></include> from employee
         <where>
             <if test="name !=null and name !=''">
               and name=#{name}
             </if>
             <if test="age !=null and age !=''">
                and age=#{age}
             </if>
             <if test="address !=null and address !=''">
                and address=#{address}
             </if>

             <if test="deptId !=null and deptId !=''">
                and deptId=#{deptId}
             </if>
         </where>
    </select>

1.2.4 set标签

用于配置update语句,用于去掉多余的,

 <!--修改-->
    <update id="update">
        update employee
        <set>
        <if test="name !=null and name !=''">
            name=#{name},
        </if>
            <if test="age !=null and age !=''">
                age=#{age},
            </if>
           <if test="address !=null and address !=''">
               address=#{address},
           </if>

            <if test="deptId !=null and deptId !=''">
              deptId=#{deptId},
            </if>
        </set>
        where id=#{id}
    </update>

1.2.5 trim标签

 可以删除或添加前缀和后缀,用来拼接SQL

<trim prefix="添加前缀" suffix="添加后缀" prefixOverride="删除前缀" suffixOverride="删除后缀">
	<if>...</if>
</trim>

 用trim代替set

 <!--配置更新操作,id是方法名称 parameterType参数类型-->
<update id="update" parameterType="User">
    update s_user
    <trim prefix="set" suffixOverrides=",">
        <if test="username !=null and username !=''">
            username = #{username},
        </if>

        <if test="password !=null and password !=''">
            password = #{password},
        </if>
        <if test="type !=null and type !=''">
            type = #{type},
        </if>
        <if test="img !=null and img !=''">
            img = #{img},
        </if>
    </trim>
    where id=#{id}
</update>

 用trim代替insert

 <insert id="insert " parameterType="User">
        insert into s_user
         <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="username !=null">
                username,
            </if>

            <if test="password !=null">
                password,
            </if>
            <if test="type !=null">
                type,
            </if>
            <if test="img !=null">
                img,
            </if>
        </trim>
         <trim prefix="values("  suffix=")" suffixOverrides=",">
         	 <if test="username !=null">
                #{username},
            </if>
            <if test="password !=null">
                #{password},
            </if>
            <if test="type !=null">
                #{type},
            </if>
            <if test="img !=null">
                 #{img},
            </if>
    	</trim>
    </insert >

1.2.6 foreach标签

用于循环拼接SQL

按多个用户名查询用户:

List findUsersByUsernames(List usernames)

select * from s_user where user_name in (‘xxx’,‘ccc’,‘ffff’)

foreach collection=“usernames” item=“name” open="(" close=")" seprator=",">

​ #{name}

<foreach collection="集合参数名称" item="变量名" open="开始符号" close="结束符号" seprator="分割符" index="下标">
	#{变量名}
</foreach> 

 <!--按多个用户名查询-->
    <select id="findUsersByUsernames" resultType="User">
        <include refid="sql_select"></include> from s_user
         where username in
         <foreach collection="usernames" item="username" open="(" close=")" separator=",">
             #{username}
         </foreach>
    </select>

2.关联查询

2.1 关联关系的分类
 表之间有几种关联关系:

1.一对一 如:一个人有一个身份证

2.一对多 如:一个部门有多个员工

3.多对一 如:多个员工属于一个部门

4.多对多 如:一个学生可以选择多门课程,一门课程也有多个学生

2.2 关联配置

 MyBatis映射文件中,在ResultMap里可以配置关联关系

 主要有两种标签来映射关联属性:

  • collection 配置集合类型的属性

  • association 配置单独对象的属性

collection和association的相关参数:

  • property 属性的名称
  • select 查询方法
  • javaType 属性的类型
  • ofType 如果属性是集合,集合中对象的类型
  • column 外键字段名

2.2.1 查询集合

1.给类型添加员工集合,这里使用collection

 public class Dept {
    private Integer deptId;
    private String deptName;
    //添加员工集合
    private List<Employee> employees;
    ...
}

2.员工类型Mapper接口

public interface DeptMapper {
    //按id查询部门
      Dept dept(Integer id);

}

3.在EmployeeMapper映射接口中定义方法

 //通过部门Id查询所有的员工
 public interface EmployeeMapper{
    List<Employee> findEmployees(Integer deptId);
}

4.DeptMapper.XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 文件和接口映射起来-->
<mapper namespace="com.hp.mybatis.mapper.DeptMapper">
    <!--实现Dept到 dept的映射-->

    <resultMap id="deptMap" type="Dept">
        <!--配置主键-->
        <id property="deptId" column="deptId"></id>
        <!--配置普通字段-->
        <result property="deptName" column="deptName"></result>

        <collection property="employees" javaType="java.util.List" ofType="Employee"
                    select="com.hp.mybatis.mapper.EmployeeMapper.findEmployees" column="deptId"></collection>
    </resultMap>



    <sql id="sql_select">
        select deptId,deptName
    </sql>

    <!--查询部门-->
    <select id="dept" resultMap="deptMap">
        <include refid="sql_select"></include> from dept where deptId=#{deptId}
    </select>

</mapper>

这里使用的是子查询的机制,在查询部门类型后,将每个类型id作为参数,调用员工接口的findEmployees方法查询元工集合。

2.2.2 查询单个对象

给Employee添加Dept属性

public class Employee {
    private Integer id;
    private  String name;
    private Integer age;
    private String address;
    private  Integer deptId;
    private Dept dept;
    ...
    }

2)员工映射文件中,使用association配置Dept 属性

<?xml version="1.0" encoding="UTF-8"?>
<resultMap id="employeesMap" type="Employee">
    <id property="id" column="id"></id>
    <result property="name" column="name"></result>
    <result property="age" column="age"></result>
    <result property="deptId" column="deptId"></result>
    <association property="dept" javaType="Employee" select="com.hp.mybatis.mapper.DeptMapper.dept" column="deptId"></association>
</resultMap>


<sql id="sql_select">
    select id,name,age,address,deptId
</sql>

<select id="findEmployees" resultMap="employeesMap">
    <include refid="sql_select"></include> from employee where deptId=#{deptId}
</select>

3、延迟加载

问题:在查询部门类型时,如果只需要类型名称,不需要该类的员工,但还是把员工查询出来,岂不浪费时间?

我们需要一种机制来优化查询

3.1延迟加载
 延迟加载也叫懒加载,需要数据时再启动查询,是MyBatis对数据库的优化机制。

3.2 配置

给MyBatis-config.xml添加配置

  <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
         <!-- 开启二级缓存 -->
		 <setting name="cacheEnabled" value="true"/>
        <!--配置懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--执行所有属性按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

3.3 测试
 在控制台查看,查询部门类型后,调用和不调用员工集合属性的SQL执行情况

4.缓存机制

4.1 缓存概述

将数据库的数据保存到内存或磁盘上,查询数据时直接访问内存或磁盘,减少对数据库的访问。

缓存作用:

1)减少数据库的负担,因为数据库连接数有限,并发量大的情况下,数据库连接耗尽,造成用户长期等待或者数据库宕机。

2)提升性能,对数据库的访问是通过TCP/IP网络进行访问,速度比较慢,通过缓存可以提高访问速度。

4.2.1 MyBatis两级缓存

  1. 一级缓存

    范围:SqlSession

    同一个SqlSession对象访问的数据,可以被缓存,下次访问直接获得不用查数据库

    默认开启,Spring整合MyBatis默认是没有开启

    失效的情况:

    1)创建新的SQLSession

    2)对缓存中的对象进行修改

  2. 二级缓存

    范围:SQLSessionFactory

    同一个SqlSessionFactory创建的所有SQLSession能共享缓存对象

    默认开启

    1)cacheEnabled 配置为true

    2)在对应的映射文件上加标签

    3)实体类需要序列化

4.2.2 缓存执行流程
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值