Mybatis框架

1. Mybatis基本介绍

1. 什么是Mybatis

百度百科:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
MyBatis 避免了几乎所有的 JDBC 代码 和 手动设置参数 以及 获取结果集 。
MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 POJO层内容 (Plain Ordinary Java Object,普通的 Java对象) 映射 成数据库中的记录。

我的理解:

  • Mybatis框架的根本是,帮助简洁的将 数据存入数据库,实现框架自动化。
  • Mybatis大大的简化了JDBC复杂的代码,让包含数据库的开发简单迅捷。

Mybatis特点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的ORM字段关系映射。
  • 提供对象关系映射标签,支持对象关系组建维护。
  • 提供xml标签,支持编写动态sql。

Mybatis框架结构示意图

1.2 持久化与持久层

(一)持久化
什么是数据持久化?

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程。
  • 内存:断电即失
  • 数据库(JDBC),IO文件持久化

数据持久化的意义:

  • 保证对象不丢失
  • 将数据从内存中解放,保证内存空间的释放。

(二)持久层
Dao层,Service层,Controller层均属于持久层...

  • 完成持久化工作的代码块
  • 层级界限十分明显,利于sql数据库代码和业务代码的解耦合,便于日常维护。

1.3 Mybatis数据库框架

  • 框架的作用在于,提供便利快捷的开发。即按规范已经设计好框架,开发者只需要个性化的填内容即可。
  • Mybatis框架,帮助程序员将数据存入到数据库中。
  • 解决了传统的JDBC中代码复杂的问题,实现框架技术的自动化。

2. 第一个Mybatis程序

2.1 环境搭建

(1)搭建数据库:

CREATE DATABASE `mybatis`;
USE `mybatis`;

CREATE TABLE `user`( 
  `id` INT(20) NOT NULL PRIMARY KEY, 
  `name` VARCHAR(30) DEFAULT NULL, 
  `pwd` VARCHAR(30) DEFAULT NULL 
  )ENGINE=INNODB DEFAULT CHARSET=utf8; 

INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
(1,'梅琳娜','123456'),
(2,'菈妮','123456'),
(3,'saber','123456')

创建成功:

(2)新建项目

  1. 新建一个普通的maven项目
  2. 删除src目录,即可将此项目视为父工程
  3. 父项目pom.xml中导入依赖
<!--导入依赖-->
    <dependencies>
    <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>
    <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
    <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

2.2 创建一个子模块

  1. 创建一个子模块(详见javaweb02笔记):new --> module --> mybatis-01
  2. 在resources文件夹下新建mybatis配置文件 mybatis-config.xml,
    在文件中引入基本的mybatis初始构建代码(官网拿到):
<?xml version="1.0" encoding="UTF-8" ?>
<!--mybatis核心配置文件-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--填写相关配置,注意sql不同版本的driver格式不同!!!-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306
                /mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!!-->
    <!-- 使用resource="Mapper.xml地址" 完成注册-->
    <mappers>
        <mapper resource="com/zfy/dao/UserMapper.xml"></mapper>
    </mappers>
</configuration>
  1. 填写更改相关配置信息

  2. 连接数据库sql,进行sql账户登录:

  3. 注意url配置,包含很多配置:

  4. 创建工具类:在java文件夹下创建文件:Java--> com.zfy.utils--> MybatisUtils.class 拿到sqlSession对象。
    工具类原理详解参照后续章节:4.7作用域与生命周期

    • 官网核心代码:
    • 按照官网指示,根据项目情况做如下修改:

7. 至此拿到sqlSession对象;该对象完全包含了 面向数据库 执行Sql命令 所需的所有方法。

2.3 编写基本流程代码

Mybatis框架项目大体包括的类如下:
①实体类
②Dao接口
③接口实现类
接下来一一实现:

  1. 数据库对象实体类:
    • 根据之前的工作,我们已经连接sql数据库,拿到数据库Mybatis,内含表格user。
    • pojo文件下创造数据库对象实体类:User.class
      该类在定义了属性后,由构造函数构成。(构造函数由alt+ins键唤出选择,自动构建)
package com.zfy.pojo;

//数据库对象 实体类,即将数据库表格实体化。
public class User {
    private int id;
    private String name;
    private String pwd;

    //Alt+ins 唤出构造函数快捷键,以下均由此构造:
    //无参构造,不勾选参数
    public User() {
    }

    //有参构造,勾选全部参数
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    //Getter and Setter 全部勾选
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    //toString构造,勾选全部参数
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  1. dao接口
    Dao层为执行sql操作的层,其主要包括两种文件:①Mapper.interface文件和 ②Mapper.xml文件。前者称为Dao接口,内部定义了数据库操作方法;后者则为接口实现类,注册了之前定义的方法。二者必须一一对应使用。

    • 针对数据库实体类对象User.class,在dao层下创建UserMapper.interface
  2. 接口实现类
    (Dao)接口实现类中 注册 接口中定义的 数据库操作方法 ,是具体 实现数据库操作(sql语句) 的程序。

  • 在User.class和UserMapping.interface的基础上创建 UserMapper.xml,改文件中定义具体的 sql语句。

  • 写完UserMapping.xml后,在mybatis-config中进行mapping注册,每一个.xml文件都要对应注册方能生效。
    注意:resource="xxx/xxxx/xxx/xxx.xml" 路径中间是以"/"分割,而不是"."。

2.4 测试

  • 编写测试类代码UserDaoTest.class,通过对象方法的顺序调用(经典三步走),执行 已经定义的数据库操作方法。

  • 运行UserDaoTest.class,拿到数据库数据,程序成功。

2.5 Mybatis框架流程总结(重点)

(1)Mybatis框架下sql操作的基本流程:

  • 包括父子项目的pom.xml在内,我们总共需要创建/修改8个程序文件。
  • 其中2个pom.xml配置文件,2个Mybatis基础配置文件,3个数据库操作相关文件,1个测试文件。
  • 数据库中的1个表,需要对应 一套3个 操作文件。以表User为例,分别是:
  • ①pojo层中的 数据库对象实体类文件User.class;②Dao层的对应 数据库接口文件 UserMapper.interface;③Dao层对应的接口实现类文件:UserMapper.xml
    程序文件顺序排列如下

(2)各文件作用简析
这里对2.1-2.3节内容各步骤作用进行一个概述总结:

  • 1.父项目的 pom.xml 用于导入 Mybatis框架依赖,共享给所有的子项目。
  • 2.子项目的 pom.xml 用于定义 各子项目的个性化需求。
  • 3.Mybatis-config.xml 用于 引入Mybatis核心配置;连接数据库;配置Dao接口实现类的映射路径等
  • 4.MybatisUtils.class 工具类,用于拿到 sqlSession对象,该对象包含了所有的sql操作。
  • 到前4步为止,即做好了Mybatis的前置准备工作,接下来是具体的表格对象sql操作。
  • 5.根据数据库表格 User,在pojo层中 创建 数据库对象实体类 User.class,该对象即代表了 数据库表 User。
  • 6.在Dao层 创建Dao接口文件 UserMapper.interface其中初步定义了数据库操作的相关方法(包括:方法名,接受形参,返回参数等),这些方法需要在Mapper.xml中进行注册,并赋予具体的 sql语句。
  • 7.步骤6的基础上,在Dao层创建 Dao接口实现类:UserMapping.xml,注册接口类中定义的方法,并赋予具体的 sql语句。
  • 8.方法实现代码,通过经典的三步走(对象方法的顺序调用)运行已经 定义/注册好的 数据库操作方法

3. Mybatis框架下实现CURD增删查改(重点)

上一节我们已经提到,在数据库连接、注册和工具类对象已经完备的情况下,需要定义具体的数据库操作方法。
数据库操作方法由三个文件顺序配合完成。三个文件分别是:①dao接口对象文件;②接口对象实现文件;③方法调用类

三个文件的作用:
①dao接口对象文件:初步定义方法,包括方法名称(接受形参),返回参数等。
②接口对象实现文件:顾名思义,实现接口文件的方法。根据①中定义的 数据库操作方法类型(CURD)进行对应注册,并在注册标签对内 写具体的sql操作语句,以此对方法进行具体实现。从功能的角度来看,这个文件最关键。
③方法调用类:通过对象方法的顺序调用(经典三步走)调用①、②中定义注册的 数据库操作方法 。详见2.4节最后一张图。

下面以表User为例,介绍增删查改的代码:

3.1 增

(1)UserMapper.interface,dao接口类:

//定义方法1:插入一个用户(增)
int addUser(User user);

(2)UserMapper.xml,dao接口实现类:

    <!-- 插入(增添)语句注册 -->
    <insert id="addUser" parameterType="com.zfy.pojo.User">
        insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd})
    </insert>

(3)方法实现类,UserMapperTest.java:
注意,增删改 操作均需要提交事务。通过语句sqlSession.commit();

    //方法一:增加一条数据
    @Test
    public void addUser(){
        //第一步:获得SqlSession对象,该对象由MybatisUtils程序拿到,可以执行所有的sql操作。
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //第二步:由SqlSession对象的方法getMapper,从对应的 数据库接口类 中拿到 数据库接口对象。
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //第三步:执行 dao接口类 中定义(注册)好的方法。
        mapper.addUser(new User(4,"爱蜜莉雅","123456"));

        //提交事务
        sqlSession.commit();
        //关闭连接,节省资源
        sqlSession.close();
    }

3.2 删

(1)UserMapper.interface,dao接口类:

    //定义方法2:删除一条数据
    int deleteUser(int id);

(2)UserMapper.xml,dao接口实现类:

    <!-- 删除语句注册 -->
    <delete id="deleteUser" parameterType="com.zfy.pojo.User">
        delete from mybatis.user where id = #{id};
    </delete>

(3)方法实现类,UserMapperTest.java:
注意,增删改 操作均需要提交事务。通过语句sqlSession.commit();

    //方法二:删除一条数据
    @Test
    public void deleteUser(){
        //第一步:获得SqlSession对象,该对象由MybatisUtils程序拿到,可以执行所有的sql操作。
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //第二步:由SqlSession对象的方法getMapper,从对应的 数据库接口类 中拿到 数据库接口对象。
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //第三步:执行 dao接口类 中定义(注册)好的方法。
        mapper.deleteUser(4);

        //提交事务
        sqlSession.commit();
        //关闭连接,节省资源
        sqlSession.close();
    }

3.3 查

(1)UserMapper.interface,dao接口类:

    //定义方法3:查询全部的用户(查)
    List<User> getUserList();

    //定义方法4:根据ID查询用户(查)
    User getUserById(int id);

(2)UserMapper.xml,dao接口实现类:

    <!-- 查询语句注册 -->
    <select id="getUserList" resultType="com.zfy.pojo.User">
        select * from mybatis.user
    </select>
    <!-- 查询语句注册 -->
    <select id="getUserById" parameterType="int" resultType="com.zfy.pojo.User">
        select * from mybatis.user where id = #{id}
    </select>

(3)方法实现类,UserMapperTest.java:
查询操作无需提交事务

    //方法三:获取表User的所有数据
    @Test
    public void getUserList(){

        //第一步:获得SqlSession对象,该对象由MybatisUtils程序拿到,可以执行所有的sql操作。
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //第二步:由SqlSession对象的方法getMapper,从对应的数据库接口类中拿到 数据库接口 对象。
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //第三步:执行 数据库接口类 中定义好的方法。
        List<User> userList = mapper.getUserList();

        //检验方法执行结果:从集合中遍历user对象
        for (User user : userList){
            System.out.println(user);
        }

        //最后一步:关闭SqlSession,节省内存资源。
        sqlSession.close();
    }

    //方法四:由Id在表中进行指定查询
    @Test
    public void getUserById(){
        //第一步:获得SqlSession对象,该对象由MybatisUtils程序拿到,可以执行所有的sql操作。
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //第二步:由SqlSession对象的方法getMapper,从对应的数据库接口类中拿到 数据库接口 对象。
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //第三步:执行 数据库接口类 中定义好的方法。
        User user01 = mapper.getUserById(1);

        sqlSession.close();
    }

3.4 改

(1)UserMapper.interface,dao接口类:

    //定义方法5:修改一个用户(改)
    int updateUser(User user);

(2)UserMapper.xml,dao接口实现类:

    <!-- 修改语句注册 -->
    <update id="updateUser" parameterType="com.zfy.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id};
    </update>

(3)方法实现类,UserMapperTest.java:
注意,增删改 操作均需要提交事务。通过语句sqlSession.commit();

    //方法五:修改一条数据
    @Test
    public void updateUser(){
        //第一步:获得SqlSession对象,该对象由MybatisUtils程序拿到,可以执行所有的sql操作。
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //第二步:由SqlSession对象的方法getMapper,从对应的 数据库接口类 中拿到 数据库接口对象。
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //第三步:执行 dao接口类 中定义(注册)好的方法。
        mapper.updateUser(new User(4,"爱蜜莉雅碳","123456"));

        //提交事务
        sqlSession.commit();
        //关闭连接,节省资源
        sqlSession.close();
    }

4. 配置

4.1 Mybatis核心配置文件

  • mybatis-config.xml
  • Mybatis 的配置文件包含了影响 Mybatis行为的设置和属性信息。
  • 配置大全(来自Mybatis官方文档)

4.2 环境配置(environment)##

  • 配置中可以定义(包含)多套Mybatis环境,再指定选择哪一套运行。
  • 每一套环境定义在 标签对<environment></environment>内;所有的环境标签对又包含在 标签对<environments></environments>内。
  • 每一套环境由两个关键参数构成:1.事务管理器;2.数据源。
  • 环境配置信息参考如下:

(1)事务管理器:

  • 一共有两个事务管理器可以选择:JDBC|MANAGED,默认为JDBC。
  • 官方解释文档如下:

(2)数据源与数据库连接池选择:

  • <dataSource type="POOLED">种type有三种选择:UNPOOLED|POOLED|JNDI,其中POOLED为默认选项。
  • UNPOOLED:不使用池连接,即数据用完就回收。
  • POOLED:启用数据库连接池,这是一种 使得并发web应用 快速响应请求 的处理方式。即数据用完后缓存在数据连接池,等待/快速响应下次使用。

4.3 属性(properties)##

(1)概念:

  • 我们可以通过properties属性来实现 引用配置文件。
  • 这些属性都是可以外部配置且可以动态替换的,既可以在典型的Java属性文件中配置,也可以通过properties元素的子元素来传递。
  • xml中各标签对有规定的位置顺序,<properties>必须位于<configures>内的首位。
    (2)实操:
  1. 在resource文件夹下新建,编写配置文件 db.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&amp;characterEncoding=UTF-8
  1. 在核心配置文件中引入:
    • 注意,xml中各标签对有规定的位置顺序,<properties>必须位于<configures>内的首位。

4.4 设置(setting)

重要的配置文件设置如下:

  • 开启缓存:

  • 懒加载,提高效率:

  • 启动驼峰命名规则,自动从 经典数据库列名 映射为 Java属性名。

  • 指定Mybatis所用日志的具体实现,未指定时将自动查找。

4.5 Mapper映射器

  • 在配置中配置映射器有三种方式:①resource指定、②clsaa指定、③package指定。
  • 按照规范,接口类 和 接口实现类 应该同名,且处在同一文件夹内。
  • 推荐使用 resource指定单个映射文件,package指定包内映射文件。

4.6 类型别名(typeAliases)

  • 类型别名是为 Java类型设置一个短名字,它只和XML配置有关,用于减少类全名的冗余。
  • 有两种类别名的设置方式:①给类单独指定别名,②指定一个包package,其内部的class会自动注册默认别名。
  • 注册别名之后,需要使用该类时,直接使用别名即可。
    • 改名前,类引用必须为全名:
    • 在配置类定义别名,使用推荐的 指定包类:
    • 改名后,类引用为简称/别名。可以看见,极大的简化了代码量:

4.7 生命周期和作用域(重要理解)

(1)官方文档说明:
关于应用Mybatis框架所创建的3实例 官方说明文档:

(2)我的理解:

  1. SqlSessionFactoryBuilder

    • 该对象仅仅用于创建SqlSessionFactory对象,创建后者完成后,前者可以被销毁。
    • 基于上一条特性,该对象一般定义为局部变量(方法变量),即方法调用完成后销毁。
  2. SqlSessionFactory(重点)

    • 该对象可以想象为:数据库连接池
    • SqlSessionFactory对象一旦被创建,那么在应用运行期间一直存在,不能销毁或者再重复创造。
    • 重复创造该对象,会造成严重的并发问题,导致程序崩溃。
    • 该对象的作用域一般定义为 全局变量(应用作用域)。
    • 常使用单例模式或者静态单例模式。
    • 该对象视需求(响应)源源不断的创造(多个)SQLSession对象。
  3. SqlSession(重点)

    • SqlSession对象是连接到连接池的一个请求。即每个请求的方法中都要创建该对象。
    • 在请求的方法结束前,必须关闭该对象sqlSession.close();,节省资源。
    • 从该对象中可以拿到mapper对象即 数据库实体类所对应的 接口类,mapper对象执行所定义的所有数据库操作。
  4. mapper对象

    • mapper对象执行在所对应的 接口类/接口定义类 中已经定义好的数据库操作方法。
    • mapper类是执行数据库操作的最终对象。

5. 对象类属性与数据库字段

5.1 解决对应表格名称不一致问题

  • 我们主要关注可能出现的 对象类属性名 与 数据库字段名 不一致的情况。
  • 使用resultMap解决这一问题
  • 举例说明,对象类包含属性名:id, username, password;数据库表包含列名:user_id, user_name, hashed_password。
    使用resultMap对象确定二者之间的映射关系,解决这一问题。

5.2 resultmap对象

resultMap元素说明:

  • resultMap元素是MyBatis中最强大的元素。
  • resultmap的优秀之处在于,虽然你已经对它相当的了解,但是无需显式的应用它。
  • resultMap的设计思想是:对于简单的语句无线配置显性的结果映射,而对于复杂的语句只需要描述它们的关系即可。

6. 日志

日志,是帮助我们便捷读懂程序执行的具体过程,方便错误排查。

6.1 日志工厂

  • 如果一个数据库操作出现了异常,我们需要排错,这时我们就需要日志工具。
  • 日志工厂就是现在的日志工具,其种类选择在配置中设置。
    • 官网中记录支持的日志工厂选项:
    • 使用<setting>标签,key-value的形式配置。其中,key是logImpl,value为其支持的选择日志类。
    • 执行数据库操作(查询表user所有数据),查看输出日志:

6.2 Log4j

(1)什么是Log4j?

百度百科:
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;
我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

信息精炼:
Log4j可以控制日志信息的输送目的地,其可以输送到 控制台,文件,GUI组件等等地方。
Log4j可以定义每一条日志信息的级别,从而更加细致的控制日志的生成。
Log4j是通过在配置文件配置完成的。

(2)使用log4j

  1. 导入log4j依赖。

  2. 在资源文件夹 resource 下创建log4j配置文件:

  3. 按照网上资料,编写需要的log4j配置文件:

  4. 在mabatis-configure.xml中将日志工厂选择为log4j。

7. 使用注解开发

7.1 面向接口编程(重点)

(1)为什么要面向接口编程?

  • 面向接口编程有,解耦,可拓展,分层开发等优点;
    在分层开发中,上中层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好。
  • 在一个面向对象的系统中,系统的各项功能是由许许多多不同对象协调完成的。
    在这种情况下,各个对象内部是如何实现自己功能的,对于系统的整体设计人员来说是不那么重要的。
  • 各个 对象之间 的协作关系 是系统设计的关键,小到不同类之间的通信,大到各模块之间的交互,这些是系统设计的主要工作内容。
    面向接口编程就是按照系统设计的思想来进行的。

(2)关于接口的理解

  • 接口思想的本质:定义 与 实现 分离。先设计定义,以此搭建系统骨架,再进行功能实现。
    定义:包括名称,规范,约束等。
    实现:包括具体的功能实现。
  • 接口本身反应了系统设计人员对于系统的抽象理解,是顶层设计。
  • 接口应有两类:
    • 抽象类接口(abstract class):对一个个体(类/对象)的抽象。
    • 抽象面接口(interface):对一个个体某一方面的抽象。
  • 由上述定义可知,一个个体只能有一个抽象类,但是可能有很多个抽象面。

(3)接口类实例说明:

  • dao层内每一个数据库对象都有其对应的 接口类 和 接口实现类。

  • 创建接口类文件,即 XXX.interface

    • 接口类文件是从 系统设计的角度对该部分提出功能需求
    • 接口类中仅定义 约束,规范,和方法的基本信息,不包括方法实现的具体内容
    • 对应的 接口实现类 程序中再定义方法实现的具体内容。
  • 创建接口实现类文件,这里以mybatis框架内的 xxx.xml 为例:

    • 接口实现类 在此具体定义 接口类中 所定义的方法。

(4)三个面向的区别:

  1. 面向对象:万物皆对象的思想。即考虑问题时,以对象为单位,考虑其属性及方法。
  2. 面向过程:考虑问题时,以一个具体的流程(事务过程)为单位,考虑其实现。
  3. 面向接口:从系统设计的角度出发,宏观整体的把握系统架构,由接口定义(功能)需求。

7.2 使用注解开发

  1. 接口中定义的方法 通过注解的方式 直接定义功能实现:
    • 以数据库操作为例,注解就描述了具体的 sql 语言。
    • 方法 形参中使用注解 @Param(“”),表示方法需要接收的 传递数据 。后续再跟正常的数据类型和形参名字。
    • 在sql语句中,数据传输 尽量使用 #{} 进行包裹,此为规范/安全的形式。
@Delete("delete from user where id = #{uid}")  //注解实现具体的数据库操作方法(sql语句)
int deleteUser(@Param("uid") int id)  //方法形参中使用注解@Param("xx")表示方法接收的参数。
                                      //xx为方法接收的参数(来自请求),后面是 数据类型 和 形参名字
  1. 在核心配置文件中 直接绑定接口:
<-- 绑定接口 -->
<mappers>
    <mapper class="com.zfy.dao.UserMapper"/>
</mappers>

3. 使用注解进行开发的原理
本质:反射机制的实现
底层:动态代理。

8. Mybatis框架执行流程

Mybatis整体执行流程如图所示:

9. Lombok

9.1 什么是lombok?

百度百科:
Lombok项目是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能。
Lombok使开发者可以通过定义一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的java模型对象,如POJO层对象。
Lombok让开发者不需要再写getter、setter或equals方法,只要有一个注解,你的类就有一个功能齐全的构建器、自动记录变量等等。

概念精炼:

  1. Lombok是一个java库,其意义是省略 类中大量重复的模块化代码开发,取而代之的是 封装好的Lombok方法标准库。
  2. Lombok用于 自动为类构造通用方法,如 getter、setter、equals等方法。在简单的java模型对象,如POJO层中尤为方便。
  3. 在导入Lombok库依赖之后,可以通过在 类上 添加注解 的形式,启用Lombok。
  4. Lombok中定义的方法,不支持多参数构造器重载。有必要的话,必须自己编写lombok中不存在/不合适的方法。

9.2 使用Lombok进行开发

  1. 在IDEA中安装/使用Lombok插件。
    • 从Lombok插件可以看到:其包含众多注解,不同注解包含(定义)不同方法。
  2. 项目中导入Lombok的jar包,即依赖。
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
  1. 在编写实体类时 使用Lombok注解 即可在此类中自动生成对应的方法。
    • 原始的pojo层中简单java实体类程序:
    • 删除所定义的方法,可以看到此时该实体类是只包含基础属性的了。
    • 添加对应的Lombok注解进行开发,pojo层一般使用@Data @AllArgsConstructor @NoArgsConstructor 自动生成方法:

9.3 关于Lombok的争议

优点:
1.能够通过注解的形式自动生成构造器:getter/setter、equals、hashcode、toString等方法,提高了开发效率。
2.让代码变得简介,无需去过多关注简单重复的方法代码。
3.属性做修改时,也简化了维护这些属性所生成的getter/setter等方法。

缺点:
1.不支持多种参数构造器的重载,需要时得自己写。
2.省去了方法构造的麻烦,但是大大降低了源码的可读性和完整性,降低了阅读舒适度。

一位资深工程师的评价:

这是一款低级趣味的插件,不建议使用。
JAVA发展到今天,各种插件层出不穷,如何甄别插件的优劣?
能够从架构上优化你的设计的,能够提高应用程序性能的,能够实现高度封装可拓展的,这些是优秀的。
lombok这种插件,已经不仅仅是插件了,它改变了你的源码习惯。事实上,这些被简化的代码就算写上去又何妨?
如果Java家族到处充斥着这样的东西,那么不过是一坨披着金光的狗屎,迟早会被取代。

10. 关联查询/联表查询

10.1 复杂查询环境创建

  • 在sql数据库中创建 Student 和 Teacher 两张表,表之间存在多对一和一对多关系。
USE `mybatis`

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 
INSERT INTO teacher(`id`, `name`) VALUES (2, '张老师'); 
INSERT INTO teacher(`id`, `name`) VALUES (3, '王老师'); 


CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
  • 由sqlyog架构设计器可以看出,多个学生对应一个老师。两张表之间确实存在多对一关系。
  • 至此,联表查询前置条件创建成功。

10.2 多对一查询

需求提出:查询所有学生信息,并包含对应的老师名字。

  • 由数据库搭建可知,多名学生对应一个老师。这是通过学生的tid字段和老师的id字段相对应实现的。
  • pojo层student,其中属性 teacher是对象,在数据库中无对应字段:
  • pojo层teacher:

(1)需求解析:

  • 问题的关键在于,Student对象有一个属性为 Teacher,而原始的数据库文件中student表中无此字段,仅有对应的 tid 字段。
  • 问题转为,如何将数据库中的 tid 字段与 对象中的属性 对应起来。
  • 我们使用 resultMap 结果集映射解决这个问题。
  • 具体来说,又有两种方式:①结果嵌套查询,②查询嵌套查询。

(2)直接查询实验:
思路分析:
1.执行sql联表查询语句,查询所有学生信息和对应的老师名字。
2.因为student类中 属性 teacher 在数据库中并无对应的字段,所以查询结果中 teacher对象信息空缺。

操作流程:

  • 接口类StudentMpper.interface,并在其中定义方法 public List<Student> getStudent();
  • 在接口实现类StudentMpper.xml中直接执行 sql语句 联表查询:
  • 在测试文件中编写测试方法:
  • 查询结果如下,学生对应的老师信息为null:

(3)结果嵌套查询
思路分析:
1.使用sql语句进行联表查询,使用 resultMap 结果集映射,解决student类中 属性 teacher 对象信息缺失问题。
2.resultMap 结果集映射,将student类中 属性 teacher 指定为javaType类型:Teacher类 。
3.嵌套描述Teacher类中的 属性(property)与 数据库中字段(column)的对应关系。

操作流程:

  • 接口类StudentMpper.interface,并在其中定义方法 public List<Student> getStudent01();

  • 在接口实现类StudentMpper.xml中直接执行 sql语句 联表查询,并使用resultMap结果集映射。

    • resultMap结果集映射用于指定,对象类中属性 与 数据库表中 字段的对应关系。
    • 其中还包括 属性是 对象/集合 的情况。
    • 属性为对象时,使用标签对说明其信息;属性为集合时,则使用标签对
    • 在对应的标签对内,嵌套说明 属性对象的信息。
  • 测试类文件方法测试:

  • 查询结果如下,学生所对应的老师信息已经显示:

(4)查询嵌套查询

  • 仍然使用resultMap实现,思路与结果嵌套查询有所不同:
    • 将sql查询分为两步,1.查询学生信息;2.在1的结果下查询老师信息。
    • 对第一步sql使用resultMap,又用resultMap锚定第二步sql,完成最终查询。

10.3 一对多查询

需求:查询老师信息,并列出老师所对应的学生。

  • 与10.2问题高度类似,区别在于:多对一的属性是 对象,而一对多的属性是 集合。
  • 也分为查询嵌套和结果嵌套。

(1)结果嵌套查询:

(2)查询嵌套查询:

(3)运行结果:

10.4 联表查询总结(重点)

10.4.1 两种类型的联表查询

(1)结果嵌套查询(推荐)

  • 关系描述较为简单,即嵌套描述 类与数据库 的关系即可。
  • sql语句较为复杂,通常为原生sql联表查询语句,建议先sql调试后再复制。

(2)查询嵌套查询

  • sql语句简单,将整体需求分为若干步简单的sql语句。
  • 但是描述对象关系较为复杂,容易出错。

10.4.2 resultMap相关标签对/属性介绍

(1)<assosiation><assosiation/>
该标签对用于描述 属性为对象 时的情况。
(2)<collection><collection/>
该标签对用于描述 属性为集合 时的情况。
(3)javaType="":
该字段用于指明实体类中属性所对应的对象种类。
(4)ofType="":
用于说明集合内的数据类型,即泛型中的约束类型。

11. 动态SQL

  • 动态sql是指根据输入的查询条件的不同,后台使用不同的sql语句。
  • 相较于传统的sql语句而言,这里多了一个判断的过程。

11.1 IF语句

  • 在mybatis框架中,可以使用if语句对输入信息进行判别,从而调用相应的sql语句。
  • if语句是以标签对 <if>的形式存在的。如果标签对内条件满足,则执行sql语句,反之则略过。
    if查询示例:
  • 接口类中定义方法,该方法接收形参为map。
  • 接口实现类 定义具体方法,使用if的sql查询。
    <!-- 动态sql -->
    <!-- 使用if进行查询条件判别,if标签对内条件成立时,执行if标签对中sql语句,反之略过 -->
    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from mybatis.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>
  • 编写测试类方法:
  • 测试:
    • 不传入任何参数进行查询,即查出所有信息。
    • 传入查询参数:key-value:"title-Java"如此简单,即查询题目是Java如此简单的所有博客。
    • 传入查询参数:"author, 狂神说",即查询作者是狂神说的所有blog。
    • 查询结果,以author为例。可以看到,输入的sql语句发生了变化,if语句生效:

11.2 choose(when, otherwise)

11.3 Trim(where, set)

Z 遇到的典型问题

z1 配置文件无法加载的问题

  • 当写好了sql查询的相关文件后,运行发现无法找到 .xml 配置文件
  • 此处需要在 maven父项目的 pom.xml中添加代码,以手动解决此问题:
    <!-- 解决maven项目中,配置文件无法导出或生效的问题 -->
    <!-- 分别设置 路径 和 格式 ,再将过滤器打开 -->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

Z2 xxxMapper.xml路径详解

  1. xxxMapper.xml为接口实现类文件,其中定义具体的操作方法。
  2. 该文件为.xml文件,按照规范其应当存放在 resources 文件夹路径下:
  3. 该文件为 接口类 所对应的 接口实现类,同样出于另一个规范,这两者应该存在一同一个文件夹内。
  4. 程序执行之前会进行编译,真正执行的是编译后的文件,即 target文件夹内文件。
  5. 根据2,3条所示,在resources文件下创造 接口类文件存放路径 同名包路径。
    接口类 一般存在于 com.zfy.dao 文件下,故创建 resources-com.zfy.dao文件夹,
    该文件夹内存放dao层 接口类xxxMaper.interface 所对应的 接口实现类文件 xxxMapper.xml。
  6. 编译后,dao层所对应的接口类和接口实现类即处在同一文件路径下了:
  7. 命名空间和映射路径都要为绝对限定路径,包含完整包名。

posted @ 2022-08-17 21:28  青梧成林2022  阅读(87)  评论(0)    收藏  举报