DAY03-mybatis

作者: 建国同学 | 来源:发表于2020-04-24 14:05 被阅读0次

    一、 mybatis步骤

    1. 新建表(查看mysql的编码:show variables like ‘%char%’)
    2. 新建 Maven 项目和添加依赖和插件
    3. 在资源目录下添加db.properties、mybatis-config.xml、log4j.properties 配置文件
    4. 编写实体类
    5. 编写Mapper xml 文件
    6. 编写MyBatisUti工具类获取session对象
    7. 编写测试类

    二、 Mapper接口

    之前存在的问题

    • namespace.id使用字符串填入查询的参数,容易编写错误
    • 第二个参数的类型是Oeject所以不被检查传入的类型而容易出错

    使用Mapper接口

    使用Mapper接口后,不存在DAO类,项目结构如下:

    • image.png
    • mapper xml文件和mapper 类保持统一路径,这样编译之后它们的字节码就会在一个路径下
    • XML 命名空间用其对应接口的全限定名;
    • Mapper 接口的方法名要和 Mapper XML 文件元素(select | update | delete | insert) id 值一样;


      image.png
    • 方法的返回类型对应 SQL 元素中定义的 resultType / resultMap 类型;
    • 方法的参数类型对应 SQL 元素中定义的 paramterType 类型
    • 定义Mapper接口


      image.png

    Mapper接口的原理

    • 通过打印接接口,发现打印的是:class com.sun.proxy.$Proxy5,底层使用的是动态代理(后面 Spring 再讲),生成 Mapper 接口的实现类。

    • 接口是规范,实质做的实现还是要由实现类对象来做,而这个实现类不需要我们写,实现类对象也不由我们创建,这些都 MyBatis 使用动态代理帮我们做了;
      我们只需提供 Mapper 接口对应 Mapper XML 文件,获取实现类对象的时候传入 Mapper 接口就可以了(不然 MyBatis 也不知道你要获取哪个 Mapper 接口的实现类对象);
      至于实现类中操作方式底层还是和之前的一样,因为 Mapper XML 命名空间是使用 Mapper 接口的全限定名,方法名又与对应 XML 元素 id 一致,所以可以通过获取调用方法所在 Mapper 接口的权限名和方法名,拼接出 namespace + id,再配合调用方法的实参就可以像之前一样操作了。

    三、 MyBatis的参数处理

    @Param注解

    • 使用@Param注解解决范式,解决接口只支持一个参数的情况
    • 本质相当于构建一个Map对象,key为注解 @Param的值,value为参数的值。


      image.png

    集合/数组参数

    当传递一个 List 对象或数组对象参数给 MyBatis 时,MyBatis 会自动把它包装到一个 Map 中,此时:
    List 对象会以 list 作为 key,数组对象会以 array 作为 key,也可以使用注解 @Param 设置 key 名。

    四、 MyBatis 的 # 和 $

    1、相同点

    都可以获取对象(Map 对象或者 JavaBean 对象)的信息。

    2、不同点

    使用 # 传递的参数会先转换为,无论传递是什么类型数据都会带一个单引号;
    使用 $ 传递的参数,直接把值作为 SQL 语句的一部分;
    使用 #支持把简单类型(八大基本数据类型及其包装类、String、BigDecimal 等等)参数作为值;
    使用 $ 不支持把简单类型参数作为值;
    使用 # 好比使用 PrepareStatement,没有 SQL 注入的问题,相对比较安全;
    使用 $ 好比使用 Statement,可能会有 SQL 注入的问题,相对不安全。
    

    总结

    若需要作为 ORDER BY 或 GROUP BY 子句获取参数值使用 $;
    若需要作为其它子句获取参数值使用 #。

    五、动态SQL

    动态SQL是MyBatis 的强大特性之一,解决了拼接 SQL 语句的痛苦
    动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。
    &gt : >
    $lt : <

    六、动态SQL之if和where

    这里test属性里取值是用$符号去取值,此时参数类型为BigDecimal类型,需要在接口形参加注解@Param
    List<Employee> querByMinSalary(@Param("minSalary")BigDecimal minSalary);

        <select id="querByMinSalary" resultType="Employee">
            SELECT id, name, sn, salary, deptId FROM employee 
            <if test="minSalary != null">
                WHERE salary &gt;= #{minSalary}
            </if>
        </select>
    

    七、动态SQL之set

    set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,若里面条件都不成立,就会去除 SET 关键字。其用来解决更新时丢失数据的问题。

    不完善的实现

    <update id="update">
            UPDATE employee 
                <if test="name != null">name = #{name},</if>
                <if test="sn != null">sn = #{sn},</if>
                <if test="salary != null">salary = #{salary},</if>
                <if test="deptId != null">deptId = #{deptId},</if>
            WHERE id = #{id}
    </update>
    

    问题:虽然可以解决更新丢失数据的问题,但会造成多逗号或者少逗号的问题(比如就第一个条件成立)

    使用set元素实现

    <update id="update">
            UPDATE employee 
            <set>
                <if test="name != null">name = #{name},</if>
                <if test="sn != null">sn = #{sn},</if>
                <if test="salary != null">salary = #{salary},</if>
                <if test="deptId != null">deptId = #{deptId},</if>
            </set>
            WHERE id = #{id}
    </update>
    

    八、动态SQL之foreach

    动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候,这里就会使用到foreach元素。

    image.png
    image.png

    九、 关系概述

    保存:页面的数据 ----> 使用 Java 对象封装 ---> 通过 MyBatis ---> 数据库表的数据
    查询:数据库表的数据 ---> 通过 MyBatis ---> 封装成 Java 对象 ---> 页面展示数据

    需要解决什么问题

    怎么使用 Java 类设计来表示对象之间关系;
    怎么使用数据库表设计来表示数据之间关系;
    怎么通过 MyBatis 配置来映射上面两者(翻译)。

    对象关系分类

    泛化关系
    实现关系
    依赖关系
    关联关系
    聚合关系
    组合关系

    关联关系

    A 对象依赖 B 对象,并且把 B 作为 A 的一个成员变量,则 A 和 B 存在关联关系。
    在 UML 中依赖通常使用实线箭头表示。

    • 按照导航性分:
      1)、单向:只能从 A 通过属性导航到 B,B 不能导航到 A。
      2)、双向:A 可以通过属性导航到 B,B 也可以通过属性导航到 A。

    • 按照多重性分
      一对一,一对多,多对一,多对多。

    • 如何判断对象的关系
      判断都是从对象的实例上面来看的;
      判断关系需要根据对象的属性;
      \color{#FF0000}{ 判断关系必须确定具体需求 }

    十、单向多对一之保存

    image.png

    十一、 向多对一之额外SQL查询

    image.png

    十二、 单向多对一之多表查询

    步骤:

    • image.png

      需求:查询所有员工及其对应部门。


      image.png

    额外SQL查询N+1问题

    需求:查询所有员工及其对应部门。
    假设在employee表中有N条数据,每一个员工都关联着一个不同的部门id。
    当在查询所有员工时,就会发送 N+1 条语句。
    1 条:SELECT * FROM employee;
    N 条:SELECT * FROM department WHERE id = ?

    使用resultMap处理结果集映射

    image.png
    • image.png

    十三、单向一对多之保存

    需求:保存一个部门和两个员工,且这两个员工都是这个部门的。
    建议集合对象直接 new 出来,避免空指针。


    image.png

    存在的问题:

    遇到问题是保存子员工表中的员工数据没有部门 id。

    解决:

    在 many 放添加一个 Long 类型的 deptId,在保存部门之后把部门的 id 值设置到员工对象这个 deptId 属性再保存员工。

    十四、单向一对多之额外SQL查询

    需求:(根据id)查询部门,并把其部门的员工信息也查询出来。

    存在的问题:

    发现只能查询出部门信息,员工信息没有查询出来,怎么办?

    1. 手动额外发送SQL去传递该部门的id去查询员工出来,再把查询的员工手动存到该部门的的employees属性上;
    2. 使用 MyBatis 的额外SQL来完成。

    使用collection发送额外SQL

    image.png

    十五、单向多对多之保存

    需求:
    保存两个学生和两个老师,且这两个老师都教了这个两个学生。

    步骤:

    • image.png
    • 插入时需要在中间表插入数据,以实现学生和教师的联系


      image.png

    十六、单向多对多之额外SQL查询

    需求:
    根据id查询学生,并查询其老师。

    • 查询学生


      image.png
    • 教师


      image.png

    十七、单向多对多之删除

    需求:
    根据id删除学生。

    • 注意:要先删除中间表的联系 ,因为该表可能有外键约束

    • 删除中间表的联系


      image.png
    • 删除去除关系的学生


      image.png

    相关文章

      网友评论

        本文标题:DAY03-mybatis

        本文链接:https://www.haomeiwen.com/subject/wcqxwhtx.html