Mybatis 知识点

Mybatis 知识点

1.1 Mybatis 简介

1.1.1 什么是 Mybatis

  • Mybatis 是一款优秀的持久层框架
  • 支持定制化 SQL、存储过程及高级映射
  • Mybatis 几乎避免了所有的 JDBC 代码和手动设置参数以及获取结果集
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO 为数据库中的记录

1.1.2 为什么需要 Mybatis

  • 更方便的将数据存入到数据库中
  • 传统的 JDBC 代码太复杂。简化,自动化
  • 减少了50%以上的代码量,比JDBC更简洁
  • Mybatis 的优点
    • 简单易学
    • 灵活
    • sql 和代码分离,提高了可维护性
    • 提供映射标签,支持对象与数据库的 orm 字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供 xml 标签,支持编写动态 sql

1.1.3 如何获取 Mybatis

maven 仓库获取

  • 可直接用以下代码引入自己的 maven 仓库中

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.5.13version>
dependency>

Github 获取源码

  • 下载地址:Releases · mybatis/mybatis-3 (github.com)

Mybatis 知识点_第1张图片

中文文档

  • 可以帮助你更好的了解 Mybatis
  • 文档地址:mybatis – MyBatis 3 | 入门

1.2 第一个 Mybatis 程序

编写第一个 Mybatis 程序首先需要有一个具体步骤:

搭建环境–> 导入 Mybatis–>编写代码–>测试

1.2.1 搭建环境

  • 新建数据库,随便添加一张表,添加一些数据,便于测试

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `userId` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `userName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名称',
  `userAge` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户年龄',
  PRIMARY KEY (`userId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三', '12');
INSERT INTO `user` VALUES (2, '李四', '15');
INSERT INTO `user` VALUES (3, '王五', '18');

SET FOREIGN_KEY_CHECKS = 1;

  • 创建一个 maven 项目
  • 导入三个 maven依赖
    • mysql驱动
    • mybatis
    • junit
    <dependencies>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.13version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.33version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13.2version>
            <scope>testscope>
        dependency>

    dependencies>

1.2.2 编写 mybatis 的核心配置文件

  • 在 resources 文件夹新建一个名为 mybatis-config.xml 的 xml 文件

Mybatis 知识点_第2张图片

  • 将以下代码粘贴进核心配置文件

DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      dataSource>
    environment>
  environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  mappers>
configuration>
  • 以上 property 标签中的 value 值,就是我们在 JDBC 中编写配置文件对应的
  • 例如 driver 代表驱动类的位置等等
  • 下面按照我自己的项目中的写法,示例

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?TRUE&useUnicode=TRUE&characterEncoding=UTF-8&serverTimezone=GMT%2B8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            dataSource>
        environment>
    environments>
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    mappers>
configuration>

1.2.3 编写 Mybatis 工具类

每个 Mybatis 的应用都是一个以 SqlSessionFactory 的实例为核心的

SqlSessionFactory 可以通过 SqlSessionFactoryBuilder 来获取

**而 SqlSessionFactoryBuilder 可以从 XML 配置文件来构建出 SqlSessionFactory **

从 SqlSessionFactory 可以获取 SqlSession 实例

通过 SqlSession 可以直接执行已经映射的 SQL 语句

  • 创建一个 dao 包和 utils 工具包

Mybatis 知识点_第3张图片

  • 在 utils 包下创建一个工具类 MybatisUtils

  • 编写 MybatisUtils 类,获取 SqlSessionFactory 实例

package com.qiaoer.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //获取资源
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
  • String resource 的值是刚刚编写的 resource 文件夹下的 xml 文件路径

  • 通过已经获取的 SqlSessionFactory 实例,来获取 SqlSession 实例

  • 编写 getSqlSession() 方法,来获取 SqlSession 实例

package com.qiaoer.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        //获取资源
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    //获取 SqlSession 实例
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
  • 获取 SqlSession 实例后,可以使用 SqlSession 中的很多方法来对数据库进行操作

1.2.4 测试,编写代码

  • 编写实体类

Mybatis 知识点_第4张图片

  • User 实体类代码
package com.qiaoer.entity;


public class User {

  private int userId;
  private String userName;
  private String userAge;

  public int getUserId() {
    return userId;
  }

  public void setUserId(int userId) {
    this.userId = userId;
  }

  public String getUserName() {
    return userName;
  }

  public void setUserName(String userName) {
    this.userName = userName;
  }

  public String getUserAge() {
    return userAge;
  }

  public void setUserAge(String userAge) {
    this.userAge = userAge;
  }

  public User() {
  }

  public User(int userId, String userName, String userAge) {
    this.userId = userId;
    this.userName = userName;
    this.userAge = userAge;
  }

  @Override
  public String toString() {
    return "User{" +
            "userId=" + userId +
            ", userName='" + userName + '\'' +
            ", userAge='" + userAge + '\'' +
            '}';
  }
}

  • 编写 dao 接口

Mybatis 知识点_第5张图片

  • UserDao 接口代码
package com.qiaoer.dao;

import com.qiaoer.entity.User;

import java.util.List;

public interface UserDao {
    //获取所有用户
    List<User> getUsers();
}

  • 编写 dao 的接口实现类
  • 在 Mybatis 中,不需要在编写接口的实现类,只需要编写一个 xml 文档即可
  • 由原来的 UserDaoImpl 转换为一个 UserMapper.xml 文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.UserDao">
<!-- SQL 语句查询-->
    <select id="selectBlog" resultType="com.qiaoer.entity.User">
        select * from user
    </select>
</mapper>
  • 其中 中的 namespace 的值对应的是要实现的接口类

  • 标签中的属性

    • 当需要进行映射时,则不需要在使用 resultType
    • 而是使用 resultMap 进行映射,他的值为 的属性 id 的值
  • 代码演示

Mybatis 知识点_第18张图片

1.6 日志

1.6.1 日志工厂

  • 当我们的数据库操作出现了异常,可以使用日志来拍错
  • 日志会输出我们项目的一些信息
  • 例如 SQL 语句,查询数据的数据等待
  • 设置日志工作应使用在 MyBatis 核心配置文件中使用 标签
  • 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
  • 位于标签的第二位
  • 标签语法
    <settings>
        <setting name="设置名" value="有效值"/>
    settings>
  • logImpl 是指定 MyBatis 所用日志的具体实现,未指定时将自动查找,即设置名

  • logImpl 的有效值为

    • SLF4J
    • LOG4J(3.5.9 起废弃)
    • LOG4J2 | JDK_LOGGING
    • COMMONS_LOGGING
    • STDOUT_LOGGING
    • NO_LOGGING
  • 在核心配置文件中设置一个标准日志

  • 标准日志的值为 STDOUT_LOGGING

Mybatis 知识点_第19张图片

  • 运行结果

Mybatis 知识点_第20张图片

  • 红框内的则是标准日志输出的结果

1.6.2 Log4j

什么是 Log4j

  • 通过 Log4j 我们可以控制日志信息输出的目的地是控制台、文件、GUI组件
  • 我们可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

1、导入 Log4j 的包

  • 在使用 Log4j 前,需要先导入 Log4j 的包
  • 将以下代码导入 maven 即可

<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>

2、创建配置文件 log4j.properties

  • Log4j 配置文件主要是来创建 log4j 的运行环境
  • 可以设置 Log4j 输出信息的各种格式
  • 创建配置文件

Mybatis 知识点_第21张图片

  • 配置文件内容如下
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/qiaoer.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3、配置 Log4j 为日志的实现

  • Log4j 的值为 LOG4J
  • 示例

Mybatis 知识点_第22张图片

4、Log4j 的简单使用

  • 使用 org.apache.log4j 的 Logger 类获取当前类的日志信息
  • 示例
//获取当前类的日志信息
Logger logger = Logger.getLogger(Test01.class);
  • Test01.class 为当前类的反射对象
  • 输出不同日记级别的日志信息
//获取当前类的日志信息
Logger logger = Logger.getLogger(Test01.class);
logger.info("info:进入了 Test01");
logger.debug("debug:进入了 Test01");
logger.error("error:进入了 Test01");
  • 示例

Mybatis 知识点_第23张图片

1.7 分页

实现分页的好处:减少数据的处理量

1.7.1 Limit 实现分页

  • SQL 语句
SELECT * from user limit startIndex,pagesize;
  • startIndex 为当前页数
  • pagesize 为每页有几条数据

使用 MyBatis 实现分页

  • 接口
package com.qiaoer.dao;

import com.qiaoer.entity.User;

import java.util.List;
import java.util.Map;
public interface UserDao {
    //获取所有用户
    List<User> getUsers();
    //分页查询用户
    List<User> getUserLimits(Map<String,Object> map);
}
  • 实现类 Mpper.xml

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.UserDao">
    <resultMap id="UserMap" type="user">
        <result property="userId"   column="userId"/>
        <result property="userName" column="userName"/>
        <result property="Age"      column="userAge"/>
    resultMap>
    
    <select id="getUsers" resultMap="UserMap" >
        select * from user
    select>
     
    <select id="getUserLimits" resultMap="UserMap">
        SELECT * from user limit #{startIndex},#{pagesize};
    select>
mapper>
  • 测试类
import com.qiaoer.dao.UserDao;
import com.qiaoer.entity.User;
import com.qiaoer.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


public class Test01 {
    public static void main(String[] args) {
        //获取 SqlSession 对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取实现类
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        //获设置参数
        Map<String,Object> map=new HashMap<String,Object>();
        map.put("startIndex",2);
        map.put("pagesize",2);
        List<User> userLimits = mapper.getUserLimits(map);
        //输出结果
        for (User user : userLimits) {
            System.out.println(user);
        }
        //提交事务
        sqlSession.commit();
        //关闭 SqlSession
        sqlSession.close();
    }
}

1.7.2 RowBounds 实现分页

  • RowBounds 是在 Java 层面进行分页的
  • 不使用 SQL 语句的 Limit,将所有结果查询出来,然后再 Java代码中进行分页
  • 具体代码
import com.qiaoer.dao.UserDao;
import com.qiaoer.entity.User;
import com.qiaoer.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


public class Test01 {
    public static void main(String[] args) {
        //获取 SqlSession 对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //分层
        RowBounds rowBounds=new RowBounds(2,2);
        //获取查询所有用户方法
        List<User> userRowBounds = sqlSession.selectList("com.qiaoer.dao.UserDao.getUsers", null, rowBounds);
        //输出结果
        for (User user : userRowBounds) {
            System.out.println(user);
        }
        //提交事务
        sqlSession.commit();
        //关闭 SqlSession
        sqlSession.close();
    }
}
  • RowBounds 对象的构造方法的两个参数即对应的就是
    • 第一个参数对应当前页数
    • 第二个参数对应每页有几条数据
  • 这里不在需要获取实现类,而是直接获取要查询的方法
  • 将所有用户查询出来,然后通过 RowBounds 的参数在 Java 代码中进行分页

1.8 使用注解开发

使用注解则不需要在写实现类

直接在接口上使用注解开发

1.8.1 使用注解进行简单的开发

  • 在接口上使用注解,不需要在使用 Mapper.xml
//获取所有用户
@Select("select * from user")
List<User> getUsers();

Mybatis 知识点_第24张图片

  • 需要在核心配置文件中绑定接口
  <mappers>
        <mapper class="com.qiaoer.dao.UserDao"/>
    mappers>

Mybatis 知识点_第25张图片

  • 测试数据,向以前一样正常运行即可
import com.qiaoer.dao.UserDao;
import com.qiaoer.entity.User;
import com.qiaoer.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


public class Test01 {
    public static void main(String[] args) {
        //获取 SqlSession 对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> users = mapper.getUsers();
        //输出结果
        for (User user : users) {
            System.out.println(user);
        }
        //提交事务
        sqlSession.commit();
        //关闭 SqlSession
        sqlSession.close();
    }
}
  • 运行结果

Mybatis 知识点_第26张图片

  • 可以发现 Age 的值为空,所以简单的注解开发无法使用结果集映射
  • 推荐使用注解开发只进行简单的操作,复杂的操作还是使用 Mapper.xml 比较好

1.8.2 使用注解进行 CRUD(增删改查)

  • **在使用注解进行开发时,如果需要参数,需要在接口的参数前面加上 **

  • 如果有多个参数,则每个参数前都需要添加注解

  • 在 SQL 语句当中,获取参数时,则填写的时以注解命名的参数

//根据 年龄和名字查询用户
@Select("select * from user where userName=#{ParamUserName} and userAge=#{ParamUserAge}")
List<User> getUsersByuserAgeAnduserName(@Param("ParamUserAge") int UserAge, @Param("ParamUserName") String UserName);
  • 如果参数为一个对象,则在 SQL 语句当中,需要使用以实体类内的属性名

Mybatis 知识点_第27张图片

  • 使用注解实现 CURD
  • 接口内
package com.qiaoer.dao;

import com.qiaoer.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;
public interface UserDao {
    //获取所有用户
    @Select("select * from user")
    List<User> getUsers();
    //根据用户 姓名和 年龄查询
    //根据 年龄和名字查询用户
    @Select("select * from user where userName=#{ParamUserName} and userAge=#{ParamUserAge}")
    List<User> getUsersByuserAgeAnduserName(@Param("ParamUserAge") int UserAge, @Param("ParamUserName") String UserName);
    //增加用户
    @Insert("insert into user (userName, userAge) values (#{userName},#{Age})")
    int addUser(User user);
    //修改用户
    @Update("update user set  userName=#{userName} where userId=#{userId}")
    int updateUser(User user);
    //删除用户
    @Delete("delete from user where userId=#{UserId}")
    int delUser(@Param("UserId") int userId);
}
  • 测试类
import com.qiaoer.dao.UserDao;
import com.qiaoer.entity.User;
import com.qiaoer.utils.MybatisUtils;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


public class Test01 {
    public static void main(String[] args) {
        //获取 SqlSession 对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> users=null;
        System.out.println("=================添加用户=================");
        //添加用户
        mapper.addUser(new User(-1,"abcd","13"));
        //输出所有用户
        users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        System.out.println("=================修改用户=================");
        //修改 id 为 3 的用户
        mapper.updateUser(new User(3,"修改了","15"));
        //输出所有用户
        users= mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        System.out.println("=================删除用户=================");
        //删除 id 为 3 的用户
        mapper.delUser(3);
        //输出所有用户
        users= mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        //关闭 SqlSession
        sqlSession.close();
    }
}
  • 一定不要忘记将接口绑定在核心配置文件当中

1.8.3 关于 @Param(“”) 注解

  • 基本类型的参数或者 String 类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上!
  • 我们在SQL中引用的就是我们这里的@Param("uid“)中设定的属性名!

1.9 Lombok

1.9.1 Lombok 简介

  • Lombok 是一款 Java 开发插件
  • 可以通过一定的注解来消除业务工程中冗长和繁琐的代码
  • 尤其对于简单的 Java 模型对象(POJO)
  • 使用 Lombok 可以省出重复构建,例如 hascode 和 equals 等方法

1.9.2 Lombok 的优缺点

优点

  • 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率
  • 让代码变得简洁,不用过多的去关注相应的方法
  • 属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等

缺点

  • 不支持多种参数构造器的重载
  • 虽然省去了手动创建 getter/setter 方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度

1.9.3 Lombok 的使用

  • 在 IDEA 中安装 Lombok 插件

Mybatis 知识点_第28张图片

  • 使用 右下角这些注解就可以自动生成一些对应的方法

  • 导入 Lombok 的 jar 包,将以下代码导入 maven 仓库即可


<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <version>1.18.28version>
dependency>
  • Lombok 常用注解介绍
注解 说明
@Data 自动生成 getter、setter、toString 等方法
@NoArgsConstructor 自动生成无参构造函数
@AllArgsConstructor 自动生成全参构造函数
@Builder 自动生成 Builder 模式相关代码
@EqualsAndHashCode 自动生成 equals 和 hashCode 方法
@Setter 自动生成 setter 方法
@Getter 自动生成 getter 方法
@ToString 自动生成 toString 方法
@Slf4j 自动生成日志变量
@NonNull 标记字段为非空,生成空值检查
@RequiredArgsConstructor 自动生成带有 final 字段的构造函数
@Value 类似 @Data,不可变对象,自动生成方法
@Cleanup 自动生成资源关闭代码
@SneakyThrows 在方法中抛出异常,无需显示声明
  • 在我们的项目中一般只使用前三种注解
  • 示例,在 User 实体类中使用
package com.qiaoer.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

  private int userId;
  private String userName;
  private String Age;
}

Mybatis 知识点_第29张图片

1.10 多对一处理

1.10.1 复杂查询测试环境搭建

在进行测试之前,需要先搭建一个测试的环境

  • 导入 lombox
  • 在 myBatis 数据库当中新建两个表: teacher 和 student
  • 关联两张表并添加一些数据
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `studentId` int(11) NOT NULL AUTO_INCREMENT COMMENT '学生id',
  `studentName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '学生姓名',
  `tId` int(11) NOT NULL COMMENT '学生关联的老师id',
  PRIMARY KEY (`studentId`) USING BTREE,
  INDEX `tId`(`tId`) USING BTREE,
  CONSTRAINT `student_ibfk_1` FOREIGN KEY (`tId`) REFERENCES `teacher` (`teacherId`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, '1号学生', 1);
INSERT INTO `student` VALUES (2, '2号学生', 1);
INSERT INTO `student` VALUES (3, '3号学生', 1);
INSERT INTO `student` VALUES (4, '4号学生', 1);
INSERT INTO `student` VALUES (5, '5号学生', 1);

-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher`  (
  `teacherId` int(11) NOT NULL AUTO_INCREMENT COMMENT '教师id',
  `teacherName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '教师姓名',
  PRIMARY KEY (`teacherId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES (1, '刘老师');
  • 新建一个项目,将 核心配置文件,即 MyBatis 工具类拷过来

Mybatis 知识点_第30张图片

  • 新建两个表的实体类

Mybatis 知识点_第31张图片

  • 在核心配置文件设置实体类的别名,方便访问

Mybatis 知识点_第32张图片

  • 新建 Mapper 接口和 Mapper.xml

Mybatis 知识点_第33张图片

  • 在核心配置文件注册接口和 xml 文件

Mybatis 知识点_第34张图片

  • 测试是否可以成功运行
  • 编写一个查询所有教师的方法,并执行

Mybatis 知识点_第35张图片

Mybatis 知识点_第36张图片

1.10.2 按照查询嵌套处理(多对一)

  • 与 SQL 的子查询道理类似

  • 主要实现,根据查询出来的学生 tid,寻找对应的教师信息

  • 首先编写接口内的查询方法

package com.qiaoer.dao;

import com.qiaoer.entity.Student;

import java.util.List;

public interface StudentMapper {
    //查询所有学生信息
    List<Student> getSudent();
}
  • 编写 StudentMapper.xml

  • 先查询所有的学生信息


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.StudentMapper">

    <select id="getSudent" resultType="student">
        select * from student
    select>
mapper>
  • 在根据学生信息内的 tid 查询出老师的信息

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.StudentMapper">

    <select id="getSudent" resultType="student">
        select * from student
    select>

    <select id="getTeacher" resultType="teacher">
        Select * from teacher where teacher.teacherId=#{id}
    select>
mapper>
  • 将两个查询语句关联起来
  • 使用结果集映射 resultMap 属性,将结果关联起来
  • 复杂的结果,比如对象,集合这类的,我们需要单独进行处理
  • 处理对象需要在 标签内使用 进行处理
  • 处理集合需要在 标签内使用 进行处理
  • 在这里处理对象,应使用 标签
    • property: 指定将关联结果映射到的属性名,这里是学生实体中与老师关联的属性名。
    • column: 指定用于关联的字段名,这里是学生表中用来和老师表关联的字段名。
    • javaType: 指定关联的实体类型,这里是老师实体的类型。
    • select: 指定一个查询,用于根据关联条件获取关联的实体。这个查询会根据指定的关联条件(通常是字段值)去获取关联实体的信息
  • 关联两个查询 示例

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.StudentMapper">

    <select id="getSudent"  resultMap="StuTeacher">
        select * from student
    select>
    <resultMap id="StuTeacher" type="student">
        <result property="studentId" column="studentId"/>
        <result property="studentName" column="studentName"/>
        <association property="teacher" column="tId" javaType="teacher"  select="getTeacher"/>
    resultMap>

    <select id="getTeacher" resultType="teacher">
        Select * from teacher where teacher.teacherId=#{id}
    select>
mapper>
  • 这里的id="getTeacher" 名字随意命名即可,不要关联某些方法
  • **相对于是将getTeacher 的查询结果赋予了 Student 类的属性 teacher **
  • 这里的参数 #{id} 本质就是将 中 column 的 tid 也就是数据库查询出来的结果,当做参数来查询的

1.10.3 按照结果嵌套处理(多对一)

  • 与 SQL 的关联查询类似
  • 先编写接口内的查询方法
package com.qiaoer.dao;

import com.qiaoer.entity.Student;

import java.util.List;

public interface StudentMapper {
    //查询所有学生信息
    List<Student> getSudent();
    //查询所有学生信息
    List<Student> getSudent2();
}
  • 编写 StudentMapper.xml
  • 使用连表查将学生与老师信息全部查询出来,结果依旧需要使用结果集映射

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.StudentMapper">

    <select id="getSudent2" resultMap="">
        select student.studentId as stuId,student.studentName as stuName,teacher.teacherId as teaId,teacher.teacherName as teaName from student INNER JOIN teacher ON student.tId=teacher.teacherId
    select>
mapper>
  • 使用结果集映射 resultMap 属性,将结果关联起来
  • 对象我们依旧使用 处理,只不过这次与上次略微不同

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.StudentMapper">

    <select id="getSudent2" resultMap="StuTeacher2">
        select student.studentId as stuId,student.studentName as stuName,teacher.teacherId as teaId,teacher.teacherName as teaName from student INNER JOIN teacher ON student.tId=teacher.teacherId
    select>
    <resultMap id="StuTeacher2" type="student">
        <result property="studentId" column="studentId"/>
        <result property="studentName" column="studentName"/>
        <association property="teacher" javaType="teacher">
            <result property="teacherId" column="teaId"/>
            <result property="teacherName" column="teaName"/>
        association>
    resultMap>
mapper>
  • 这里的 标签只有两个属性
    • property 属性值对应的是 Student 实体类内的对象属性 teacher
    • javaType 属性值则对应的是 Teacher 实体类
  • 标签内的 标签则是将 teacher 属性对象内的属性关联起来
    • property 属性对于的是 teacher 属性对象内的属性
    • column 则是与之关联的数据库内查询出来的数据

1.11 一对多处理

1.11.1 环境搭建

  • 和刚才一样,只是实体类有所不同

Mybatis 知识点_第37张图片

1.11.2 按照结果嵌套处理(一对多)

  • 编写,查询所有教师方法
package com.qiaoer.dao;

import com.qiaoer.entity.Teacher;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface TeacherMapper {
    //查询所有教师
    List<Teacher> getTeachers();
}
  • **编写 TeacherMapper.xml **

  • 与多对一时非常相似,也需要结果集映射

  • 处理集合需要用到 标签

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.TeacherMapper">
    <select id="getTeachers" resultMap="TeaStudent">
        select student.studentId as stuId,student.studentName as stuName,teacher.teacherId as teaId,teacher.teacherName as teaName from student INNER JOIN teacher ON student.tId=teacher.teacherId
    </select>
    <resultMap id="TeaStudent" type="teacher">
        <result property="teacherId" column="teaId"/>
        <result property="teacherName" column="teaName"/>
        <collection property="studentList" ofType="student">
            <result property="studentId" column="stuId"/>
            <result property="studentName" column="stuName"/>
        </collection>
    </resultMap>
</mapper>
  • 标签的属性

    • property 则表示 实体类内对应的集合属性的属性名
    • ofType 的本质与 javaType 类似,表示集合的泛型对应的实体类
  • 标签内标签的属性

    • property 表示集合的泛型对应的实体类内的属性
    • column 则表示数据库查询的数据
  • 他的本质与多对一大差不差

1.11.3 按照查询嵌套处理(一对多)

  • 与多对一的本质其实大差不差
  • 唯一有区别的就是 Mapper.xml 的地方

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qiaoer.dao.TeacherMapper">
    <select id="getTeachers" resultMap="TeaStudent">
        select * from teacher
    select>
    <resultMap id="TeaStudent" type="teacher">
        <result property="teacherId" column="teacherId"/>
        <result property="teacherName" column="teacherName"/>
        <collection property="studentList" javaType="ArrayList" ofType="student" select="getStudent" column="teacherId"/>
    resultMap>
    <select id="getStudent" resultType="student">
        select * from student where tId=#{id}
    select>
mapper>
  • 标签内的属性
    • property 对应的是实体类内的集合
    • javaType 表示那个集合的类型,这里为 ArrayList
    • ofType 表示集合对应的泛型,需要些实体类的位置
    • select 指定一个查询,用于根据关联条件获取关联的实体。这个查询会根据指定的关联条件(通常是字段值)去获取关联实体的信息
    • column 则相当于一个参数,与下方的 select * from patient patientID=#{patientID}
      • foreach:遍历
      • collection:集合名称,对应 map 的 key
      • item:集合的每一项,对应 list 的每一项
      • open:sql 以什么开头
      • close:sql 以什么结尾
      • separator: sql 以什么分隔
      • 里面写拼接的 sql

      在写这类复杂的拼接 可以先在数据库中写好 正确的完整 sql 在来替换拆分

      1.12.7 sql 片段

      在使用 sql 的时候 会有一些重复性的 判断,例如上面的案例,都判断了titlegender类似于这样的 sql 就可以抽离成 sql 片段,以复用

       <update id="updatePatientInfo" parameterType="map">
              update patient
              <set>
                  <include refid="if-password-gender"/>
              set>
              <where>
                  identityNum=#{identityNum}
              where>
      update>
      
      <sql id="if-password-gender">
          <if test="password != null">
              password=#{password},
          if>
          <if test="gender != null">
              gender=#{gender},
          if>
      sql>
      
      • sql:抽离出来的 sql 片段
      • id:片段名称(见名知意)
      • include:在需要使用片段的地方,导入片段
      • refid:sql 片段名称
      • sql 片段不要包含 where 语句
      • 尽量提取简单的 sql 片段以提高,复用性

      1.12.8 script

      要在带注解的映射器接口类中使用动态 SQL,可以使用script元素。

          @Update({""})
          void updateAuthorValues(Author author);
      

      1.12.9 bind

      bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。

      <select id="selectBlogsLike" resultType="Blog">
        <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
        SELECT * FROM BLOG
        WHERE title LIKE #{pattern}
      select>
      

你可能感兴趣的:(MyBatis,mybatis)