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

    一、 mybatis步骤 新建表(查看mysql的编码:show variables like ‘%char%’)...

网友评论

    本文标题:DAY03-mybatis

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