Java_持久层_MyBatis

不定期补充、修正、更新;欢迎大家讨论和指正

目录

  • JDBC
  • MyBatis
    • 基本使用
      • 传参问题
    • 全局配置文件
    • 结果映射
      • 多表查询
    • 动态SQL
      • if标签
      • choose标签
      • foreach标签
    • 缓存
      • 一级缓存
      • 二级缓存
      • 自定义缓存
    • 源码分析
  • 整合Spring
  • MBG
  • 通用Mapper(tk Mapper)
    • 环境搭建
    • BaseMapper
    • ExampleMapper
    • RowBoundsMapper
  • MyBatis-Plus

JDBC

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

JDBC API支持用于数据库访问的两层和三层处理模型,但通常,JDBC体系结构由两层组成:

  • JDBC API:提供应用程序到JDBC管理器连接。
  • JDBC驱动程序API:支持JDBC管理器到驱动程序连接。

如以下架构图,它显示了驱动程序管理器相对于JDBC驱动程序和Java应用程序的位置
sun公司提出JDBC接口规范,各个厂商对自己的产品实现相关符合规范的驱动,
只要符合JDBC接口规范,我们都可以通过JDBC统一的API操控不同的数据库产品。
在这里插入图片描述

这里只是简单回顾JDBC,如果没学过可以参考以下视频
尚硅谷JDBC核心技术视频教程

使用JDBC来访问数据库大致可以分为以下步骤

  1. 配置账号、密码、Driver、url成功连接数据库
  2. 通过链接Connection获取PreparedStatement类
  3. 编写SQL语句,将SQL语句放入PreparedStatement中预编译
  4. 填充占位符
  5. 执行SQL语句,如果是查询SQL,还需要用ResultSet类来接收结果集
  6. 关闭资源等收尾工作

配置连接数据库的信息,获取连接和关闭资源都是重复的代码,所以这里写一个工具类来进行封装

public class JdbcUtils {

    private static Connection conn;
    static {
        try {
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc_conn.properties");//读取JDBC配置文件,自己定义
            Properties p = new Properties();
            p.load(is);

			
            String url = p.getProperty("url");//数据库URL
            String user = p.getProperty("user");//用户名
            String password = p.getProperty("password");//密码
            String driverClass =p.getProperty("driverClass");//数据库驱动

            Class.forName(driverClass);
            conn = DriverManager.getConnection(url, user, password);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throwables.printStackTrace();
        }
    }

    public static Connection getConnection() {//获取连接
        return conn;
    }
    public static void closeResource(Connection conn, PreparedStatement ps){//关闭资源
        try {
            if(ps !=null)
                ps.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if(conn !=null)
                conn.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
    public static void closeResource(Connection conn, PreparedStatement ps, ResultSet rs){//关闭资源
        try {
            if(ps !=null)
                ps.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if(conn !=null)
                conn.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if(rs !=null)
                rs.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

接下来是SQL相关的代码,这里以下表为例
Java_持久层_MyBatis_第1张图片

插入

@Override
    public void insert(Jobs jobs) {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            conn = JdbcUtils.getConnection();
                        								
            String sql = "INSERT INTO `jobs`(`job_id`,`job_title`,`min_salary`,`max_salary`)VALUE(?,?,?,?);";
			
            ps = conn.prepareStatement(sql);//预编译

            ps.setString(1,jobs.getJob_id());//填充占位符
            ps.setString(2,jobs.getJob_title());
            ps.setInt(3,jobs.getMin_salary());
            ps.setInt(4,jobs.getMax_salary());

            ps.execute();//执行

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.closeResource(conn,ps);//关闭连接
        }

    }

删除

@Override
    public void deleteByID(String ID) {
        Connection conn = null;
        PreparedStatement ps = null;

        try {
            conn = JdbcUtils.getConnection();
            String sql = "DELETE FROM `jobs` WHERE `job_id`=?;";
            ps = conn.prepareStatement(sql);
            ps.setString(1,ID);

            ps.execute();

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.closeResource(conn,ps);
        }
    }

查询

@Override
    public Jobs getByID(String ID) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;//查询就复杂些,需要接收结果集

        try {
            conn = JdbcUtils.getConnection();
            String sql = "SELECT * FROM `jobs` WHERE `job_id` = ?;";

            ps = conn.prepareStatement(sql);

            ps.setString(1,ID);

            rs = ps.executeQuery();
            if (rs.next()) {
                Jobs jobs = new Jobs();
                jobs.setJob_id(rs.getString(1));
                jobs.setJob_title(rs.getString(2));
                jobs.setMin_salary(rs.getInt(3));
                jobs.setMax_salary(rs.getInt(4));
                return jobs;
            }


        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.closeResource(conn,ps,rs);
        }
        return null;

在使用传统的JDBC中,我们可以发现诸多不便

  • CURD很多步骤相同,连接数据库,获取PreparedStatement等。
    解决方法:提出公共部分作于模板
  • 将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
    解决方法:利用反射从外部文件获取SQL语句。
  • 对于查询语句,接收结果集的过程十分繁琐
  • 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能
    解决方法:利用数据库连接池

尽管有一些简化的工具比如Dbutils和JDBCTemplate等,但能做的也很有限。
随后市面上就出现了许多持久层框架来简化开发和操作,如MyBatis、Hibernate、TopLink、Guzz、jOOQ、Spring Data。如今MyBatis占主流,同时也是主流MVC框架——SSM(Spring + SpringMVC + MyBatis)重要的一环。

MyBatis

在这里插入图片描述

什么是 MyBatis?
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
–摘自官网

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
–摘自百度百科

MyBatis官方帮助文档

基本使用

导入Mybatis
jar包:mybatis
Maven依赖


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

mysql驱动


        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.37version>
        dependency>

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

根据官方所说,SqlSessionFactory是整个MyBatis的核心,SqlSessionFactory通过SqlSessionFactoryBuilder获取,而SqlSessionFactoryBuilder可以通过XML配置文件来构造,以下为官方给出的XML配置文件模板(配置文件名根据规范一般为mybatis-config.xml)。


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">
       
        <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>

Java_持久层_MyBatis_第2张图片
接下来就可以获取SqlSessionFactory实例了,通过SqlSessionFactory可以获取SqlSession实例,而SqlSession才是真正与数据库交互的东西。

在这里插入图片描述

为了后续方便使用,可以写成工具类

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;
    
    static {
    
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

}

在测试前先把主配置文件中的mapper映射注释掉(写SQL的地方),因为这是官方给的例子,我们并没有该mapper需要映射,否则会报错
在这里插入图片描述

Java_持久层_MyBatis_第3张图片
成功获取SqlSession,但不代表能成功连接到数据库,就算连接数据库的账号密码是错误的,在这时也不会有任何提示
在这里插入图片描述
利用SqlSession向数据库做CURD操作,仍以下表为例
Java_持久层_MyBatis_第4张图片
ORM(对象关系映射),创建实体类,用于后面接收结果集
Java_持久层_MyBatis_第5张图片
按照原生JDBC,接下来就是写SQL语句了,MyBatis提供在XML中编写SQL语句的形式,这些文件我们称为mapper


DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  
<mapper namespace="org.mybatis.example.BlogMapper">
	
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  select>
  
mapper>
  • namespece:命名空间。在大型项目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在MyBatis中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个ID。只要我们能够保证每个命名空间中这个ID是唯一的,即使在不同映射文件中的语句ID相同,也不会再产生冲突了。命名空间在之前版本的MyBatis中是可选的,这样容易引起混淆因此毫无益处。现在命名空间则是必须的,且易于简单地用更长的完完全限定名来隔离语句。
  • id:全局唯一不解释
  • resultType:接收结果集的类
  • #{id}:占位符以该形式编写

命名空间是为了防止id冲突,这里简单使用完全不怕,但既然是必须的,就先创建一个接口
Java_持久层_MyBatis_第6张图片
Java_持久层_MyBatis_第7张图片
接下来很重要的一步,将我们的mapper在主配置文件中注册
Java_持久层_MyBatis_第8张图片
有些人习惯把mapper放在src目录下,会很容易遇到找不到该mapper路径的异常,因为Maven一般只读取resources下的xml文件,所以解决方法就是放在resources目录下
Java_持久层_MyBatis_第9张图片
如果偏要放在其他目录下比如这里的src,需要在pom.xml添加以下配置

<build>
        <resources>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>

接下来就可以通过sqlSession向数据库进行CURD操作了
我们先用用selectOne()方法,该方法提供两个参数,一个是mapper接口中的方法,第二个是传入的查询参数
Java_持久层_MyBatis_第10张图片
在这里插入图片描述
sqlSession的方法过于局限,同时为了避免标签冲突,更好的做法是获取mapper所绑定的接口,通过接口调用这些方法,这样不仅更安全,可读性好、传参也方便
Java_持久层_MyBatis_第11张图片
经过简单的使用,可以发现MyBatis很好地解决了原生JDBC的弊端:SQL语句在外部文件中编写,降低耦合性、结果集的接收MyBatis自动完成,只需要指定接收结果集的类即可,使得我们可以专注于SQL语句的构造。

接下来把剩下的CRUD写完,不过在实现之前导入log4j日志功能,我们只能通过SqlSession是否操作数据库成功,但是如果出错,仅仅通过SqlSession很难进行排错。

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

导入依赖

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

创建log4j的配置文件(log4j.properties,最好放在resource下)
这里是从Log4j的配置与使用详解直接扒下来的

# Global logging configuration
# 设置日志输出级别以及输出目的地,可以设置多个输出目的地,开发环境下,日志级别要设置成DEBUG或者ERROR
# 前面写日志级别,逗号后面写输出目的地:我自己下面设置的目的地相对应,以逗号分开
# log4j.rootLogger = [level],appenderName1,appenderName2,…
log4j.rootLogger=DEBUG,CONSOLE,LOGFILE

#### 控制台输出 ####
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
# 输出到控制台
log4j.appender.CONSOLE.Target = System.out
# 指定控制台输出日志级别
log4j.appender.CONSOLE.Threshold = DEBUG
# 默认值是 true, 表示是否立即输出
log4j.appender.CONSOLE.ImmediateFlush = true
# 设置编码方式
log4j.appender.CONSOLE.Encoding = UTF-8
# 日志输出布局
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
# 如果日志输出布局为PatternLayout 自定义级别,需要使用ConversionPattern指定输出格式
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p (%c:%L) - %m%n



#### 输出错误信息到文件 ####
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
# 指定输出文件路径
#log4j.appender.LOGFILE.File =F://Intellij idea/logs/error.log 
log4j.appender.LOGFILE.File =./logs/error.log 

#日志输出到文件,默认为true
log4j.appender.LOGFILE.Append = true
# 指定输出日志级别
log4j.appender.LOGFILE.Threshold = ERROR
# 是否立即输出,默认值是 true,
log4j.appender.LOGFILE.ImmediateFlush = true
# 设置编码方式
log4j.appender.LOGFILE.Encoding = UTF-8
# 日志输出布局
log4j.appender.LOGFILE.layout = org.apache.log4j.PatternLayout
# 如果日志输出布局为PatternLayout 自定义级别,需要使用ConversionPattern指定输出格式
log4j.appender.LOGFILE.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

有了日志功能,可以了解到SQL完整的执行过程,方便调试
在这里插入图片描述
在接口制定CRUD方法
Java_持久层_MyBatis_第12张图片

插入
Java_持久层_MyBatis_第13张图片
对于增删改操作,SqlSession默认是不会自动提交事务的,需要手动提交
Java_持久层_MyBatis_第14张图片

在这里插入图片描述
在这里插入图片描述
更改
在这里插入图片描述
在这里插入图片描述
Java_持久层_MyBatis_第15张图片

在这里插入图片描述

删除
在这里插入图片描述

Java_持久层_MyBatis_第16张图片
在这里插入图片描述
查询全部
查询多个结果,虽然返回值是集合,但在SQL语句返回值设置为集合中元素的类型就行
在这里插入图片描述
Java_持久层_MyBatis_第17张图片

Java_持久层_MyBatis_第18张图片

传参问题

细心的朋友可以发现在以上CRUD传参的形式都有所不同
在MyBatis中,当传参只有一个时,在SQL语句写的参数名可以随意
比如删除操作,因为不会产生歧义,名字怎么取都没关系
在这里插入图片描述
当传的参数有多个时,可以传map,SQL语句的#{}中的变量名需要和map中的key相同
在这里插入图片描述
Java_持久层_MyBatis_第19张图片
也可以通过Java Bean传递多个参数,SQL语句的#{}中的变量名和实体类的属性相同
Java_持久层_MyBatis_第20张图片
Java_持久层_MyBatis_第21张图片
Java_持久层_MyBatis_第22张图片
还有是使用@param注解的形式,这里不进行演示
MyBatis(四)SQL语句中参数传递的五种方法

还有需要注意的是 ${},#{}的区别

在很多地方,${} 的作用是直接取值,这种方式容易产生SQL注入的危险(以预编译的方式将参数设置到sql中)
而#{} 运行结果会是一个?占位符 ,和使用PreparedStatement目的一致

当然${} 并不是一无是处,可以用于分库分表排序等原生jdbc不支持占位符的地方,例如
select * from ${month}_salary order by ${name}

全局配置文件

全局配置文件的属性设置,完全可以看官方文档
mybatis-配置Java_持久层_MyBatis_第23张图片
这里学习几个常用的
属性(properties)
主要用来获取外部文件的内容,比如连接数据库的信息可以单独放到另一个文件,然后通过properties引入
Java_持久层_MyBatis_第24张图片

Java_持久层_MyBatis_第25张图片
也可以直接在标签内设置,但是优先级还是文件中的高
Java_持久层_MyBatis_第26张图片
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
比如之前mapper用到类时写的是全路径比较长
在这里插入图片描述
取别名
Java_持久层_MyBatis_第27张图片
Java_持久层_MyBatis_第28张图片

当需要某个包下有很多类需要取别名时,可以以包为单位为其下的所有类取别名
在这里插入图片描述
类的别名为类名(无视大小写)
Java_持久层_MyBatis_第29张图片

环境配置(environments)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境,所以要在< environments default=“development” >标签内选择具体的环境
Java_持久层_MyBatis_第30张图片
每套环境内都要设置transactionManager和dataSource,具体内容自己看
设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。自行了解,后续使用时会提到。
Java_持久层_MyBatis_第31张图片

结果映射

在前面select语句中,对于复杂的结果集我们常用JavaBean 或 POJO来接收,也就是resultType=‘JavaBean’,虽然看似是ResultType完成了结果集的映射,但实际上是ResultMap完成了这些事。MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。

什么时候用ResultMap呢,当数据库的字段和javaBean属性字段不一样时就可以使用(数据库字段命名一般为job_id,而Java是驼峰式命名)

之前属性名和数据库字段是一一对应的,所以直接可以用resultType接收
Java_持久层_MyBatis_第32张图片
假如改成驼峰式命名,我们来看看还能接收到结果集吗
Java_持久层_MyBatis_第33张图片
可以看到能查询到结果,但是没接收到结果集
在这里插入图片描述

在这里插入图片描述
这种情况下容易解决,我们可以在全局配置文件中的setting标签内开启驼峰命名自动映射
在这里插入图片描述
Java_持久层_MyBatis_第34张图片
在这里插入图片描述
也可以利用SQL语法中的as取别名(别忘了关掉驼峰命名自动映射,不然不知道有没有成功)
Java_持久层_MyBatis_第35张图片
还有一种方法就是用resultMap作映射了
resultMap标签有三个属性
Java_持久层_MyBatis_第36张图片
resultMap下有几个子标签,现在先使用这两个(id和result的作用一样)
在这里插入图片描述

如果数据库字段和属性名一一对应或者驼峰转换后对应,直接用resultType就行,用resultMap就多次一举了
Java_持久层_MyBatis_第37张图片
但是对于多表查询或者一些复杂的查询就不得不用resultMap来封装结果了,在此之前先了解resultMap标签内所有的属性
Java_持久层_MyBatis_第38张图片

多表查询

在先前我们已经有了一张job表
Java_持久层_MyBatis_第39张图片
现在根据job_id与另一张employee表进行多表查询(为了方便点,这里只考虑以下四个属性,以及job表的job_title属性)
Java_持久层_MyBatis_第40张图片

而这两张表结合呈现一对多的关系(以job表为主表,一个job可以有多个employee),而反过来就是多对一的关系(以employee为主表),因此使用resultMap时要对两种关系分别进行实现。

构造实体类
Java_持久层_MyBatis_第41张图片
因为job表可以查出多个employees,所以要为其添加一个列表类型的属性(这种其实方式是很不好的,当初刚学还不懂这些,因为我们要避免修改实体类,在web开发中会经常遇到实体类接收不了封装结果,这时可以另外创建一个类来包括实体类的所有属性和多出来的属性,比如vo)
Java_持久层_MyBatis_第42张图片
重写下Employees的toString方法,方便后面查看
Java_持久层_MyBatis_第43张图片
多对一
接下来先以简单的多对一关系进行实现,以下面查询结果为例
在这里插入图片描述
Java_持久层_MyBatis_第44张图片
映射文件,在主配置文件注册这些常规流程就不说了
Java_持久层_MyBatis_第45张图片
先构造select语句
Java_持久层_MyBatis_第46张图片
再构造resultMap,因为查询的主表是Employees,所以type为Employees类
Java_持久层_MyBatis_第47张图片
这段没什么好说的,都是Employees的属性,按照普通的列名-属性名进行映射就行
Java_持久层_MyBatis_第48张图片
重点是association标签,关联(association)元素处理“有一个”类型的关系

association标签下又包含四个属性,不过只用关心property和javaType
Java_持久层_MyBatis_第49张图片
简单来说
property:你想将另一张表查询的结果集放到哪个属性下,还记得在Employees表下的Jobs jobs属性吗,所以这里property=’jobs’
javaType:接收另一张表结果集的JavaBean
接下来只要完成另一张表自己的列名-属性名的映射就行了
在这里插入图片描述
test
Java_持久层_MyBatis_第50张图片
查询成功
在这里插入图片描述
在该例中,我们完全可以将多表查询等价为嵌套子查询,即先查询jobs表得到结果,在此结果上再查询employees表
因此我们可以修改成另一种形式

实现查询jobs表和employees的SQL语句,jobs直接返回结果,employees表还需要进行映射处理
Java_持久层_MyBatis_第51张图片
Java_持久层_MyBatis_第52张图片
同样重点在于association标签
property和javaType和上面一样
在这里插入图片描述
column和select的功能如下
column:连接键的列名,这里column是必选项,不像前面可以略去,因为要知道通过哪个共同的键进行查询
select:也是必选,不然怎么获得嵌套查询的结果
Java_持久层_MyBatis_第53张图片
同样成功查询
Java_持久层_MyBatis_第54张图片
一对多
当jobs作为主表时,通过job_id查询employees,显然构成了一对多的关系,但是大部分操作都相似,连SQL语句都是一样的
在这里插入图片描述

Java_持久层_MyBatis_第55张图片
接下来是关键点resultMap,association标签用于处理“有一个”类型的关联,而处理“有多个”类型的关联就需要用到collection集合标签了,collection标签的属性和association标签大部分相同,需要注意的是collection返回的类型,因为返回的是List,所以javaType得是ArrayList类型(可忽略),而ofType填才是List中元素的类型

Java_持久层_MyBatis_第56张图片
在jobs表中实现打印方法(本来不用这么麻烦,但是只取了几个字段,其他字段就不打印了)
Java_持久层_MyBatis_第57张图片
在这里插入图片描述
成功获取
在这里插入图片描述
关于多表查询的结果映射还是比较令人头大,可以参考以下视频,以及强烈建议参考官方文档
【狂神说Java】Mybatis最新完整教程IDEA版通俗易懂

动态SQL

​ 动态sql是指在进行sql操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况,是比较常用的功能。

比如在一个页面中的表单有几个传输参数(学到MyBatis应该都学过JaveWeb了)
Java_持久层_MyBatis_第58张图片
根据传输的参数动态地构造SQL语句
Java_持久层_MyBatis_第59张图片

Java_持久层_MyBatis_第60张图片
执行SQL语句
Java_持久层_MyBatis_第61张图片
原文:JDBC实现动态查询

可以发现使用原生的JDBC十分的繁琐,而且还容易漏掉空格逗号造成错误,因此MyBatis提供了强大的动态SQL,让我们摆脱这种麻烦。

Java_持久层_MyBatis_第62张图片

if标签

if标签是比较常用的功能,最常见情景是根据条件包含 where 子句的一部分
比如想查询工资大于minSalary,小于maxSalary范围的字段
在这里插入图片描述

Java_持久层_MyBatis_第63张图片
仅传入minSalary
Java_持久层_MyBatis_第64张图片
根据日志信息可以看到成功拼接了SQL语句(maxSalary为空)
在这里插入图片描述

在这里插入图片描述
在此基础上查询工资低于20000的
在这里插入图片描述

在这里插入图片描述
其实这里写的拼接语句有很大的漏洞,假如minSalary为空但maxSalary不为空
Java_持久层_MyBatis_第65张图片
就会拼接成错误的SQL语句导致报错

在这里插入图片描述
一种解决方法是在主SQL中添加where 1=1(保证后续的语句肯定执行),拼接SQL统一用逻辑连接符开头

Java_持久层_MyBatis_第66张图片
这样SQL语句就不会出错了
在这里插入图片描述
另一种方法是使用trim标签,这个就自己去官网看。

choose标签

choose标签和swith-case语句类似,只会进入一个分支
比如我们可以根据job_id或job_title查询字段,如果一个属性存在,另一个就属性就不使用
在这里插入图片描述
为了规范点,以后查询条件都放在where标签内
Java_持久层_MyBatis_第67张图片
只用job_title查询(when标签)
Java_持久层_MyBatis_第68张图片
在这里插入图片描述
同时用两个属性查询,可以看到当排在前面的分支符合后,就算后面有其他分支符合条件也不会进入
在这里插入图片描述
默认情况(otherwise标签)
在这里插入图片描述

foreach标签

foreach常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
foreach使用难点比if和choose复杂些,主要在于参数的选择,foreach标签内有以下几个参数

  • item:表示集合中每一个元素进行迭代时的别名。(必选)
  • index:指定一个名字,表示在迭代过程中每次迭代到的位置。(可选)
  • open:表示该语句以什么开始(如果是 in 条件语句,以’('开始 )(可选)
  • separator:表示在每次进行迭代之间以什么符号作为分隔符(如果是 in 条件语句,以’,'作为分隔符)(可选)
  • close:表示该语句以什么结束(如果 in 条件语句,以’)'开始 )(可选)

使用 foreach 标签时,最关键、最容易出错的是 collection 属性,该属性是必选的,但在不同情况下该属性的值是不一样的,主要有以下 3 种情况:

  • 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list。
  • 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array。
  • 如果传入的参数是多个,需要把它们封装成一个 Map,当然单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。
  • 摘自MyBatis foreach标签

比如传入List,通过多个job_id查询多个字段
Java_持久层_MyBatis_第69张图片
另外提一下,我们知道形参不同就可以函数重载,但在mybatis这是不允许的,因为标签id必须得唯一
Mybatis的XxxMapper.xml中能否配置重载方法
Mybatis的mapper接口函数重载问题

Java_持久层_MyBatis_第70张图片
Java_持久层_MyBatis_第71张图片
在这里插入图片描述

缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大地提升查询效率
MyBatis默认定义了两级缓存:一级缓存和二级缓存

一级缓存

一级缓存是默认开启的(SqlSession级别的缓存,也称为本地缓存)
如下,当我们先后分别查询同一字段,因为第一次查询的结构仍在缓存中,所以并不需要再次从数据库查询,大大增加了高并发的效率,因为我们知道数据从内存中读取远比从磁盘IO读取来的快
Java_持久层_MyBatis_第72张图片

演示需要用到日志功能,这里不使用log4j,使用MyBatis自带的日志功能换换口味,在主配置文件的setting标签开启就行

	<settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>

Java_持久层_MyBatis_第73张图片

一级缓存在几种情况下会失效,官方的给的文档说到select语句的结果会被缓存,但是insert、update、delete语句会刷新缓存

Java_持久层_MyBatis_第74张图片

如下,在两次查询同一字段中,我们还更新了字段,尽管更新的字段和要查询的字段无关,MyBatis为了保证ACID原则也会再次从数据库查询
Java_持久层_MyBatis_第75张图片

Java_持久层_MyBatis_第76张图片
对此我们可以看各个标签内的属性,对于select语句,默认使用缓存
在这里插入图片描述
对于增删改操作,没有useCache属性,并且flushCache默认为true,所以一执行就会刷新缓存
在这里插入图片描述

二级缓存

二级缓存也叫全局缓存,是基于namespace级别的缓存,一个命名空间对应一个缓存(二级缓存并不是来解决一级缓存失效的问题的)
一个会话查询一个缓存,查询的数据会存放在当前会话的一级缓存中,如果该会话关闭,其缓存也会消除。
但我们可以使其保存在二级缓存中,新的会话查询就可以从二级缓存读取,不同的mapper查出的数据会放在自己对应的缓存中
要启用全局的二级缓存,需要现在主配置文件开启。

<setting name="cacheEnabled" value="true"/>

因为二级缓存的作用域是namespace,也就是mapper映射文件,所以哪个映射文件需要二级缓存,在该mapper映射文件中添加< cache >即可

Java_持久层_MyBatis_第77张图片
该标签下有五个属性

  • eviction(清除策略):缓存清空策略,默认为LRU
    1. LRU – 最近最少使用:移除最长时间不被使用的对象。
    2. FIFO – 先进先出:即队列,按对象进入缓存的顺序来移除它们。
    3. SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
    4. WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象
  • flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
  • size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
  • readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
  • type(自定义缓存)除了上述自定义缓存的方式,也可以通过实现你自己的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。

创建两个会话,在第一次会话关闭后,仍然查询相同的字段,很明显可以看到两次查询的对象是相同的。
Java_持久层_MyBatis_第78张图片

Java_持久层_MyBatis_第79张图片

关闭二级缓存后
Java_持久层_MyBatis_第80张图片

自定义缓存

MyBatis毕竟不是专门做缓存的,所以在一些复杂的情况下就需要用其他更强大的缓存,比如EhCache、Redis。自行了解
MyBatis自定义缓存——Redis实现
MyBatis自定义缓存——EhCache实现

源码分析

MyBatis底层源码解析 (详细)

整合Spring

目前来说,Mybatis常与Spring、SpringMVC一起组成SSM框架,也是目前主流的MVC框架来完成一个JavaWeb项目的开发,因此学习整合Mybatis和Spring(SpringMVC是Spring下的子框架,整合Spring就行)是十分必要的。

使用 Spring IoC 可以有效的管理各类的 Java 资源,达到即插即拔的功能;通过 Spring AOP 框架,数据库事务可以委托给 Spring 管理,消除很大一部分的事务代码,配合 MyBatis 的高灵活、可配置、可优化 SQL 等特性,完全可以构建高性能的大型网站。
毫无疑问,MyBatis 和 Spring 两大框架已经成了 Java 互联网技术主流框架组合,它们经受住了大数据量和大批量请求的考验,在互联网系统中得到了广泛的应用。使用 MyBatis-Spring 使得业务层和模型层得到了更好的分离,与此同时,在 Spring 环境中使用 MyBatis 也更加简单,节省了不少代码,甚至可以不用 SqlSessionFactory、 SqlSession 等对象,因为 MyBatis-Spring 为我们封装了它们。
–《Java EE 互联网轻量级框架整合开发》

篇幅原因这里不进行实现
Spring:
Java学习_Spring_IoC
Java学习_Spring_AOP

MyBatis-Spring
MyBatis 与 Spring 整合

MBG

MBG(MyBatis-generator),是MyBatis框架中代码生成器。在此之前,我们先了解逆向工程的概念。

逆向工程(又称逆向技术),是一种产品设计技术再现过程,即对一项目标产品进行逆向分析及研究,从而演绎并得出该产品的处理流程、组织结构、功能特性及技术规格等设计要素,以制作出功能相近,但又不完全一样的产品。逆向工程源于商业及军事领域中的硬件分析。其主要目的是在不能轻易获得必要的生产信息的情况下,直接从成品分析,推导出产品的设计原理。

比如制造一个零件,正向的流程是先用绘图工具比如AutoCAD、UD进行绘制图纸和建模,然后进入生产车间通过车床之类的加工出来。而逆向工程是先有实物,通过扫描实物获取实物的各个参数,在计算机中分析数据,再经过修正处理就可以获得接近实物的图纸,再通过图纸加工出实物,大大减少了设计流程。

在前面使用MyBatis中,我们要根据数据库表创建实体类、DAO层的各个接口以及mapper映射文件,通过逆向工程,我们就可以根据数据库表自动生成这些东西。它只需要很少量的简单配置,就可以完成大量的表到Java对象的生成工作,拥有零出错和速度快的优点,让开发人员解放出来更专注于业务逻辑的开发。

MBG的官方文档如下,目前只有英文,估计以后也不会更新了
MyBatis Generator

导入相关依赖(数据库,MyBaits这些依赖就不说了)


<dependency>
    <groupId>org.mybatis.generatorgroupId>
    <artifactId>mybatis-generator-coreartifactId>
    <version>1.3.7version>
dependency>

MGB只负责帮我们生成三类文件,上面也说过了

  • 实体类,根据ORM规则生成与数据库表对应的实体类
  • DAO层的接口
  • Mapper映射文件

根据官方文档快速开始,简单来说就是MBG生成的代码可以有几种风格,取决于在其配置文件下< context >如何配置targetRuntime这个属性。
MBG快速运行只需要三步

  1. 创建和配置配置文件
  2. 将该文件保存到合适的位置
  3. 在命令行界面运行MBG(有多种执行方式)
    Java_持久层_MyBatis_第81张图片

targetRuntime这个属性提供了四种代码生成策略
Java_持久层_MyBatis_第82张图片
这里以MyBatis3生成策略为例(MyBatis3和MyBatis3Simple的targetRuntime属性都是MyBatis3Simple,MyBatis3Simple相较于MyBatis3的配置文件只是少了< sqlMapGenerator >这个用于生成mapper映射文件的标签)
创建配置文件,将文档给的配置复制上去先

DOCTYPE generatorConfiguration PUBLIC
 "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

  <context id="simple" targetRuntime="MyBatis3Simple">
  
    <jdbcConnection driverClass="org.hsqldb.jdbcDriver"
        connectionURL="jdbc:hsqldb:mem:aname" />
        
  
    <javaModelGenerator targetPackage="example.model" targetProject="src/main/java"/>
 
    <sqlMapGenerator targetPackage="example.mapper" targetProject="src/main/resources"/>
 
    <javaClientGenerator type="XMLMAPPER" targetPackage="example.mapper" targetProject="src/main/java"/>

    <table tableName="FooTable" />
  context>
generatorConfiguration>

以这四张表为例
Java_持久层_MyBatis_第83张图片
Java_持久层_MyBatis_第84张图片

接下来就可以运行MBG了,执行的方法有以下几种,因为我们用XML来配置,所以用下面这种方式执行
Java_持久层_MyBatis_第85张图片
把文档给的代码改改(主要是配置文件的路径)执行

  List<String> warnings = new ArrayList<String>();
   boolean overwrite = true;
   File configFile = new File("generatorConfig.xml");
   ConfigurationParser cp = new ConfigurationParser(warnings);
   Configuration config = cp.parseConfiguration(configFile);
   DefaultShellCallback callback = new DefaultShellCallback(overwrite);
   MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
   myBatisGenerator.generate(null);

Java_持久层_MyBatis_第86张图片
到目标包查看生成的代码
Java_持久层_MyBatis_第87张图片
Java_持久层_MyBatis_第88张图片
对于实体类,MBG可以自动将数据库字段变成驼峰式命名
在这里插入图片描述
Java_持久层_MyBatis_第89张图片
对于DAO层接口和Mapper映射文件,MBG会自动生成最基础的SQL语句
Java_持久层_MyBatis_第90张图片
Java_持久层_MyBatis_第91张图片
MBG的配置文件中还有很多配置没说,可以自行阅读官方文档和下篇文章
MyBatis——MyBatis Generator插件使用(配置详解)

通用Mapper(tk Mapper)

尽管MBG已经很大程度提高我们的效率,但在使用 MBG 过程中,如果数据库字段变化很频繁,就需要反复重新生成代码,并且由于 MBG 覆盖生成代码和追加方式生成 XML,导致每次重新生成都需要大量的比对修改。除了这个问题外,还有一个问题,仅仅基础的增删改查等方法,就已经产生了大量的 XML 内容,还没有添加一个自己手写的方法,代码可能就已经几百行了。

由于MBG 中定义的大多是常用的单表方法,为了解决前面提到的问题,也为了兼容 MBG 的方法避免项目重构太多,在 MBG 的基础上结合了部分 JPA 注解产生了通用 Mapper。通用 Mapper 可以很简单的让你获取基础的单表方法,也很方便扩展通用方法。使用通用 Mapper 可以极大的提高工作效率。
-摘自MyBatis 为什么需要通用 Mapper ?

环境搭建

官方文档:通用 MAPPER 3

通用mapper也叫tk mapper,通用Mapper需要在Mybatis和Spring的整合上进行集成


<dependency>
    <groupId>tk.mybatisgroupId>
    <artifactId>mapperartifactId>
    <version>4.1.5version>
dependency>

导入相关依赖后,需要在Spring的配置文件上进行一些修改,即Mapper扫描配置,正常扫描包的路径是mapper映射文件所在的目录
Java_持久层_MyBatis_第92张图片
这里需要修改为通用Mapper的类,其作者为了方便大家,这里只需要将类最前面的org改为tk即可,同时扫描的路径不再是mapper映射文件,而是DAO层接口所在的包
在这里插入图片描述
通用Mapper帮助我们省略mapper.xml的编写,想当然必须要花费别的代价,它要求我们的DAO接口继承它提供的BaseMapper接口
这里仍以jobs表为例
Java_持久层_MyBatis_第93张图片
实体类直接使用MBG生成的(注意实体类是Job,表是jobs,挖下坑)
Java_持久层_MyBatis_第94张图片
继承接口,泛型传入相应的实体类
Java_持久层_MyBatis_第95张图片
这里看不出什么,查看Mapper接口就会发现大有文章,Mapper接口又继承了以下接口,看接口的名称也能猜个大概
Java_持久层_MyBatis_第96张图片

先看BaseMapper,很显然该接口提供了基本的CRUD功能,一层一层往下看
Java_持久层_MyBatis_第97张图片

Java_持久层_MyBatis_第98张图片

Java_持久层_MyBatis_第99张图片

每个接口看太麻烦,直接看BaseMapper的结构,看它都继承到了些什么方法
Java_持久层_MyBatis_第100张图片
为了方便测试这些方法,使用JUnit测试工具来测试
引入依赖


<dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>4.13.1version>
    <scope>testscope>
dependency>

我们的接口需要把继承的方法实现,IDEA中Ctrl+I 快捷键就可以批量实现
Java_持久层_MyBatis_第101张图片
Java_持久层_MyBatis_第102张图片
随后在当前接口快捷键 Ctrl + Shift + t 就可以生成测试文件
Java_持久层_MyBatis_第103张图片

Java_持久层_MyBatis_第104张图片
最终会在test包下生成测试文件
Java_持久层_MyBatis_第105张图片
然后取出相关的bean就可以测试
在这里插入图片描述

BaseMapper

以简单的selectAll()为例,取出表中所有记录
Java_持久层_MyBatis_第106张图片
报错了,因为数据库中没有job这张表,前面故意留的坑,可以看出通用mapper自动找的表应该是与实体类名称一致的表,对于这种情况可以修改数据库表名或实体类名字,但显然不合理,因为这些基本是不动的。
在这里插入图片描述
只需要在实体类上加个注解就行
Java_持久层_MyBatis_第107张图片

测试成功
Java_持久层_MyBatis_第108张图片
同样的如果属性名和列名不一致也要添加相应的注解(下划线会自动转换为相应的驼峰式,所以这里没出错)
假如数据库字段变成驼峰式也对应不上,那肯定会报错

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
同样的,这种情况加上一个注解就可以解决

在这里插入图片描述
如果有些属性是数据库没有的字段,可以加上@Transient,不参与SQL语句
在这里插入图片描述

接下来测试其他方法

selectOne(),查询一个结果,这里需要传入相应实体类,并返回查询结果,传入的参数主要用于封装查询条件的(只能判断’='的条件,对于大于小于这些其他判断条件暂时判断不了)
在这里插入图片描述
Java_持久层_MyBatis_第109张图片
Java_持久层_MyBatis_第110张图片
该方法限制了只返回一个结果,如果查询结果有多个结果会报错
在这里插入图片描述
这时得调用select()来接收
在这里插入图片描述

selectByPrimaryKey(),根据主键来查询
在这里插入图片描述
Java_持久层_MyBatis_第111张图片
没查询到结果, 我们检查下SQL语句,发现这一幕,所有字段都根据给的主键值来查询,显然是查询不到的
在这里插入图片描述
这是因为通用mapper不知道哪个属性是主键,只能全部注入了,解决方法在主键属性上加上注解
在这里插入图片描述
Java_持久层_MyBatis_第112张图片

insert(),插入实体类,返回生效的行数,没什么好说的
在这里插入图片描述
Java_持久层_MyBatis_第113张图片
在这里插入图片描述

insertSelective(),作用跟insert一样,区别在于它不会插入非空的字段
Java_持久层_MyBatis_第114张图片
在这里插入图片描述

其他方法大同小异,自己去官方文档了解
Mapper 接口大全

ExampleMapper

BaseMapper接口的功能了解后,现在来看ExampleMapper
Java_持久层_MyBatis_第115张图片
ExampleMapper用于QBC查询

QBC(Query By Criteria)是一种面向对象的查询方式,这种查询方式以函数API的方式动态地设置查询条件,组成查询语句。

在前面在用select方法时是直接用实体类封装查询条件,这种方法只能简单地来根据字段是否等于封装条件来查询。如果想查询更复杂些的,比如要查询薪资在某个范围内(minSalary

在通用Mapper中,使用QBC查询先创建Example实例,可以从Example类的结构看出Criteria和Criterion是其内部类,需要通过Example实例获取
Java_持久层_MyBatis_第116张图片
我们看到Criteria提供了大量封装好的查询条件
Java_持久层_MyBatis_第117张图片
绝大多数方法需要以下这两种参数类型,显然就是属性名和属性值(仔细看看就会发现该类构造查询条件其实就是拼接字符串来实现的)
Java_持久层_MyBatis_第118张图片

在这里插入图片描述

大概结构了解后,开始测试。比如想要查询薪资在(4000-5000)或(10000-20000)间的job
SQL语句应为

(minSalary >=4000 AND maxSalary<=9000) OR (minSalary >=10000 AND maxSalary<=20000) 

该SQL语句分为两部分,所以需要创建两个Criteria
在这里插入图片描述
为Criteria封装查询条件(GreaterThanOrEqualTo:大于或等于 LessThanOrEqualTo:小于或等于,如果是或逻辑,把and改成or就行)
Java_持久层_MyBatis_第119张图片
然后合并两个Criteria需要调用example的or或and

在这里插入图片描述
调用ExampleMapper的方法传入example参数
在这里插入图片描述

在这里插入图片描述
当我看到生成的SQL语句我陷入了沉思,怎么又多出了一个查询条件!

在这里插入图片描述
经过几次试验,我猜测example会自动将第一个Criteria的查询条件封装到自己内部,所以example进行逻辑链接时就不用链接第一个了

如下,不对Criteria进行链接
在这里插入图片描述
可以发现封装的条件和参数和第一个Criteria一致
在这里插入图片描述
在这里插入图片描述
这样的话只用链接第二个Criteria就行了
在这里插入图片描述
在这里插入图片描述
还有一个坑是example自动链接的第一个Criteria是根据什么来决定的,是根据Criteria创建还是Criteria封装条件后?
我把2放到1前,让2先进行创建
Java_持久层_MyBatis_第120张图片
根据参数的参数可以知道是根据创建的顺序来链接了
在这里插入图片描述
感觉该作者设计得不太好,不管怎么样还是查询到了结果(个人宁愿自己写SQL语句)
剩下的方法不测试了,只要英语和SQL语句有点基础都能根据方法名了解怎么使用
Java_持久层_MyBatis_第121张图片

RowBoundsMapper

Java_持久层_MyBatis_第122张图片

该接口的功能用于分页操作
需要两个参数,第一个封装查询条件的类,第二个RowBounds用于封装分页的参数
在这里插入图片描述
在这里插入图片描述
该类的结构十分简单,除了构造器就是get方法
Java_持久层_MyBatis_第123张图片
这里就不封装查询条件了
Java_持久层_MyBatis_第124张图片
可以看到该方法并不是在SQL语句后面拼接分页逻辑,而是查询所有数据到内存,再到内存中进行分页
Java_持久层_MyBatis_第125张图片

MyBatis-Plus

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

官方文档:MyBatis-Plus
Java_持久层_MyBatis_第126张图片
实际上中MP会用的更多,MP是比MBG和通用mapper更强大的工具,其核心功能和上两者相同,所以这里不对MP进行了解,相信大家在学会MBG和通用mapper后,加上文档能很容易上手MP
Java_持久层_MyBatis_第127张图片
这些工具固然好用,但还是建议大家先把基本的SQL语句用熟练了再使用工具简化开发

你可能感兴趣的:(Java,数据库,mybatis,mysql,java,数据库)