Java框架:Mybatis【详细】

一、Mybatis概述

1.1ORM框架是什么?

Object Relation Mapping: 对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的User类,去对应数据库中的一张user表,类中的属性和表中的列一一对应。User类就对应user表,一个User对象就对应user表中的一行数据。


1.2Mybaits的概念

  • MyBatis本是apache的一个开源项目iBatis , 2010年改名为MyBatis。
  • MyBatis是一个基于Java的半自动ORM框架 ,是 JDBC 和 Hibernate 的替代方案 。
  • MyBatis 支持普通 SQL查询,存储过程,高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性, 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索 。
  • Mybatis内部封装了 JDBC,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,开发者只需要关注 SQL 语句本身,使用 XML 文件注解的方式实现 SQL 的灵活配置 。

1.3Mybatis的优点与缺点

优点:

  • MyBatis 是免费且开源的。
  • 与 JDBC 相比,减少了 50% 以上的代码量。
  • MyBatis 是最简单的持久化框架,小巧并且简单易学。
  • MyBatis 相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL 写在 XML 中,和程序逻辑代码分离,降低耦合度,便于同一管理和优化,提高了代码的可重用性。
  • 提供 XML 标签,支持编写动态 SQL 语句。
  • 提供映射标签,支持对象与数据库的 ORM 字段关系映射。
  • 支持存储过程。MyBatis 以存储过程的形式封装 SQL,可以将业务逻辑保留在数据库之外,增强应用程序的可移植性、更易于部署和测试。

缺点:

  • 编写 SQL 语句工作量较大,对开发人员编写 SQL 语句的功底有一定要求。
  • SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

1.4MyBatis和Hibernate的区别

Hibernate 和 MyBatis 都是目前业界中主流的对象关系映射(ORM)框架,它们的主要区别如下。

1.sql 优化方面

  • Hibernate 使用 HQL(Hibernate Query Language)语句,独立于数据库。不需要编写大量的 SQL,就可以完全映射,但会多消耗性能,且开发人员不能自主的进行 SQL 性能优化。提供了日志、缓存、级联(级联比 MyBatis 强大)等特性。
  • MyBatis 需要手动编写 SQL,所以灵活多变。支持动态 SQL、处理列表、动态生成表名、支持存储过程。工作量相对较大。

2.开发方面

  • Hibernate 是一个全表映射的框架,只需提供 POJO 和映射关系即可。

  • MyBatis 是一个半自动映射的框架,因为 MyBatis 需要手动匹配 POJO 和 SQL 的映射关系。

3.缓存机制比较

  • Hibernate 的二级缓存配置在 SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置缓存。
  • MyBatis 的二级缓存配置在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且 Mybatis 可以在命名空间中共享相同的缓存配置和实例,通过 Cache-ref 来实现。

4.应用场景

  • Hibernate 适合需求明确、业务固定的项目,例如 OA 项目、ERP 项目和 CRM 项目等。
  • MyBatis 适合需求多变的互联网项目,例如电商项目、金融类型、旅游类、售票类项目等。

二、Mybatis的核心对象

MyBatis 有三个基本要素:

  • 核心接口和类:java类

  • MyBatis核心配置文件(mybatis-config.xml):配置数据库源、配置加载映射文件的路径

  • SQL映射文件(mapper.xml):写sql的地方

    MyBatis 的核心接口和类,如下所示。
    在这里插入图片描述

Myatis操作数据的步骤:

  1. 首先获取 SqlSessionFactoryBuilder对象,可以根据 XML 配置文件或者 Configuration 类的实例构建该对象。

  2. 然后获取 SqlSessionFactory 对象,该对象实例可以通过 SqlSessionFactoryBuilder 对象来获取。

  3. 有了 SqlSessionFactory 对象之后,就可以进而获取 SqlSession实例。SqlSession 对象中完全包含以数据库为背景的所有执行 SQL 操作的方法,用该实例可以直接执行已映射的 SQL 语句。


SqlSessionFactoryBuilder :

SqlSessionFactoryBuilder 会根据配置信息或者代码生成 SqlSessionFactory,并且提供了多个 build() 方法重载,重要的就是这几个。

  • build(InputStream inputStream, String environment, Properties properties)
  • build(Reader reader, String environment, Properties properties)
  • build(Configuration config)

SqlSessionFactory:

SqlSessionFactory 是工厂接口而不是现实类,他的任务就是创建 SqlSession。 SqlSessionFactory 通过 openSession() 方法来获取 SqlSession 实例 。

SqlSessionFactory的生命周期和作用域: SqlSessionFactory 对象一旦创建,就会在整个应用程序过程中始终存在。 最佳作用域是 Application 。

SqlSession:

SqlSession 是用于执行持久化操作的对象,类似于 JDBC 中的 Connection。它提供了面向数据库执行 SQL 命令所需的所有方法,可以通过 SqlSession 实例直接运行已映射的 SQL 语句。

对象说明
Executor接口执行器.统一调度StatementHandler、PrepareStatement、ResultHandler对象执行对应的SQL
StatementHandler使用的数据库中的Statement执行操作 相当于字符串拼接
PrepareStatement使用SQL传参的方式处理
MappedStatement负责对SQL封装,用于存储需要映射的SQL语句及参数等信息
ResultHandler对最后的结果进行封装

SqlSession 的用途主要有两种:

  1. 获取映射器。让映射器通过命名空间和方法名称找到对应的 SQL,并发送给数据库,执行后返回结果。
  2. 直接通过 “命名空间(namespace)+SQL id” 的方式执行 SQL,不需要获取映射器。这是 iBatis 版本留下的方式。

SqlSession生命周期和作用域:SqlSession 对应一次数据库会话。 需要注意的是,每个线程都有自己的 SqlSession 实例,SqlSession 实例不能被共享,也不是线程安全的。因此 SqlSession 的作用域范围是 request 作用域或方法体作用域内。


三、Mybatis的执行流程

在这里插入图片描述


四、Mybatis的快速使用

3.1开发环境准备

  • JDK1.8
  • IDEA2022
  • Maven:apache-maven-3.9.0
  • MySQL:MySQL8.0

3.2新建maven项目

3.3添加Maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.shenxm</groupId>
    <artifactId>demo3_mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--    mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.12</version>
        </dependency>
        <!--        mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
        <!--    junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!--    配置idea扫描xml或者properties文件 -->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

</project>

3.4MySQL创建user表

-- 创建user表
create table user
(
    user_id   int auto_increment comment '用户 ID',
    user_name varchar(255) null comment '用户名',
    status    varchar(255) null comment '用户状态',
    PRIMARY KEY (user_id)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 ;

3.5创建数据源database.properties文件

在 src\main\resources 目录下 创建 database.properties文件:用于mybatis配置文件读取数据库信息

#mysql数据库:MySQL5.7
driver=com.mysql.cj.jdbc.Driver
url= jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username=root
password=123456
#注意:MySQL5.7的driver路径为:com.mysql.jdbc.Driver

3.6编写mybatis-config.xml配置文件

在 src\main\resources 目录下 创建 mybatis-config.xml配置文件: 用于配置数据库连接和 MyBatis 运行时所需的各种特性,包含了设置和影响 MyBatis 行为的属性、映射文件的位置。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!-- mybatis的主配置文件 -->
<configuration>
    <!-- 引入外部资源: database.properties 配置文件-->
    <properties resource="database.properties"/>

    <!-- 配置环境:有助于将 SQL 映射应用于多种数据库之中 -->
    <environments default="mysql">
        <!-- 配置环境id:mysql-->
        <environment id="mysql">
            <!-- 配置事务的类型:使用JDBC的事务-->
            <transactionManager type="JDBC"/>
            <!-- 配置数据源(连接池)type="POOLED说明是使用连接池方式,节省资源 -->
            <dataSource type="POOLED">
                <!-- 配置连接数据库的4个基本信息 -->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--     指定映射配置文件的位置
        <mappers>
          1.单独加载某个映射配置文件
           <mapper resource="com/shenxm/mybatisdemo/mapper/IUserMapper"/>
          2.加载某包所有的配置文件
           <package name="com.shenxm.mybatisdemo.mapper"/>
        </mappers>   
	-->
    <mappers>
        <package name="com.shenxm.dao"/>
    </mappers>

</configuration>

3.7测试数据库连通性

在 src\test\java 目录下的 com.shenxm.DemoTest包 创建 DemoTest测试类:用输入流读取配置文件,然后根据配置文件信息构建sqlSessionFactory对象,通过sqlSessionFactory对象创建sqlSession对象,并使用sqlSession对象的方法执行数据操作。

package com.shenxm;

import com.shenxm.dao.IUserMapper;
import com.shenxm.entity.UserEntity;
import com.shenxm.utils.MybatisUtils;
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 org.junit.Test;
import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class DemoTest {
    @Test
    public void test1() throws IOException {
        // 核心配置文件classpath路径
        String resource = "mybatis-config.xml";
        // 加载配置文件
        Reader config = Resources.getResourceAsReader(resource);
        //InputStream config = Resources.getResourceAsStream(resource);
        // 构建会话工厂
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
        // 从SqlSessionFactory对象中获取SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        System.out.println(sqlSession.getConnection());
        /** 
        注意: 当我们对数据库里的表做删除修改添加的时候,一定不要忘记了加上提交(session.commit();),不然数据库里的内容不会发生改变。
        */
        // 归还连接给数据源
        sqlSession.close();
    }
}

3.8创建UserEntity类

在src\main\java目录下 的 com.shenxm.entity包创建UserEntity类:用于跟数据库字段做映射。

package com.shenxm.entity;
import lombok.Data;

@Data
public class UserEntity {
    private Integer userId;
    private String userName;
    private String status;
}

3.9创建IUserMapper接口

在src\main\java目录下 的com.shenxm.dao包创建IUserMapper接口:

import com.shenxm.entity.UserEntity;
import java.util.List;

public interface IUserMapper {
    List<UserEntity> queryUser();
}

3.10创建IUserMapper.xml文件

在src\main\java 目录下 的com.shenxm.dao.mapper包创建IUserMapper.xml:

或者

在src\main\resources 目录下 的com.shenxm.dao.mapper包创建IUserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.shenxm.dao.IUserMapper">
    <!--查询所有用户-->
	<!--<select> 标签表明这是一条查询语句,属性id用来标识这条SQL;resultType表示返回的是一个serEntity类型的值。 -->   
    <select id="queryUser" resultType="com.shenxm.entity.UserEntity">
        select * from user
    </select>
    
</mapper>

注意:

mapper接口和mapper.xml之间需要遵循一定规则,才能成功的让mybatis将mapper接口和mapper.xml绑定起来

  • mapper接口和mapper.xml的命名要一样;
  • mapper接口的全限定名,要和mapper.xml的namespace属性一致;
  • mapper接口中的方法名,要和mapper.xml中的SQL标签的id一致;
  • mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致
  • mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致

3.11数据库连接工具

Dao类中每次进行CRUD操作,都要执行一次oenSession方法来获得SqlSession对象,造成资源的浪费和代码的重复。

定义连接数据库工具,可以获得sqlsession对象。

package com.shenxm.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.Reader;

/**
 * mybatis工具类
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            // 加载配置文件
            Reader config = Resources.getResourceAsReader(resource);
            //InputStream config = Resources.getResourceAsStream(resource);
            // 构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession
     * @return SqlSession
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

3.12测试UserMapper接口

在 src\test\java 目录下的 com.shenxm.mybatisdemo包中 DemoTest测试类添加测试方法:

package com.shenxm;

import com.shenxm.dao.IUserMapper;
import com.shenxm.entity.UserEntity;
import com.shenxm.utils.MybatisUtils;
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 org.junit.Test;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class DemoTest {
    @Test
    public void test2() throws IOException {
        SqlSession sqlSession = null;
        sqlSession = MybatisUtils.getSqlSession();
        System.out.println("sqlSession.getConnection()是:"+sqlSession.getConnection());
        IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
        List<UserEntity> userList = mapper.queryUser();
        userList.forEach(System.out::println);
        // 归还连接给数据源
        sqlSession.close();
    }
}

3.13基于注解的开发

基于注解的开发,可以不写UserMapper.xml,只需要将sql写到代码里,但是后续的维护和扩展性不是很好。

这里将IUserMapper接口改成:

package com.shenxm.mybatisdemo.mapper;

import com.shenxm.mybatisdemo.po.User;
import java.util.List;

public interface IUserMapper {
    @Select("SELECT * FROM user")
    List<UserEntity> selectAll();
}

五、Mybatis的全局配置文件解析

全局配置文件中,各个标签要按照如下顺序进行配置:

<configuration>
	<!-- 配置顺序如下
     1.properties  

     2.settings

     3.typeAliases

     4.typeHandlers

     5.objectFactory

     6.plugins

     7.environments
        environment
            transactionManager
            dataSource

     8.mappers
     -->
</configuration>

5.1<properties>标签

一般将数据源的信息单独放在一个properties文件中,然后用这个标签引入,在下面environment标签中,就可以用${}占位符快速获取数据源的信息 。

<properties resource="database.properties"/>

5.2<settings>标签

用来开启或关闭mybatis的一些特性,比如可以用<setting name="lazyLoadingEnabled" value="true"/>来开启延迟加载,可以用<settings name="cacheEnabled" value="true"/>来开启二级缓存

配置项作用配置选项默认值
cacheEnabled该配置影响所有映射器中配置缓存的全局开关true|falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。在特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态true|falsefalse
aggressiveLazyLoading当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载true|false版本3.4.1 (不包含) 之前默认值为 true,之后为 false
multipleResultSetsEnabled是否允许单一语句返回多结果集(需要兼容驱动)true|falsetrue
useColumnLabel使用列标签代替列名。不同的驱动会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果true|falsetrue
useGeneratedKeys允许JDBC 支持自动生成主键,需要驱动兼容。如果设置为 true,则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)true|falsefalse
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射。 PARTIAL 表示只会自动映射,没有定义嵌套结果集和映射结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)NONE、PARTIAL、FULLPARTIAL
autoMappingUnkno wnColumnBehavior指定自动映射当中未知列(或未知属性类型)时的行为。 默认是不处理,只有当日志级别达到 WARN 级别或者以下,才会显示相关日志,如果处理失败会抛出 SqlSessionException 异常NONE、WARNING、FAILINGNONE
defaultExecutorType配置默认的执行器。SIMPLE 是普通的执行器;REUSE 会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新SIMPLE、REUSE、BATCHSIMPLE
defaultStatementTimeout设置超时时间,它决定驱动等待数据库响应的秒数任何正整数Not Set (null)
defaultFetchSize设置数据库驱动程序默认返回的条数限制,此参数可以重新设置任何正整数Not Set (null)
safeRowBoundsEnabled允许在嵌套语句中使用分页(RowBounds)。如果允许,设置 falsetrue|falsefalse
safeResultHandlerEnabled允许在嵌套语句中使用分页(ResultHandler)。如果允许,设置falsetrue|falsetrue
mapUnderscoreToCamelCase是否开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射true|falsefalse
localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速联复嵌套査询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlScssion 的不同调用将不会共享数据SESSION|STATEMENTSESSION
jdbcTypeForNull当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHERNULL、VARCHAR、OTHEROTHER
lazyLoadTriggerMethods指定哪个对象的方法触发一次延迟加载equals、clone、hashCode、toString
defaultScriptingLanguage指定动态 SQL 生成的默认语言org.apache.ibatis .script.ing.xmltags .XMLDynamicLanguageDriver
callSettersOnNulls指定当结果集中值为 null 时,是否调用映射对象的 setter(map 对象时为 put)方法,这对于 Map.kcySet() 依赖或 null 值初始化时是有用的。注意,基本类型(int、boolean 等)不能设置成 nulltrue|falsefalse
logPrefix指定 MyBatis 增加到日志名称的前缀任何字符串Not set
loglmpl指定 MyBatis 所用日志的具体实现,未指定时将自动査找SLF4J|LOG4J|LOG4J2|JDK_LOGGING |COMMONS_LOGGING |ST DOUT_LOGGING|NO_LOGGINGNot set
proxyFactory指定 MyBatis 创建具有延迟加栽能力的对象所用到的代理工具CGLIB|JAVASSISTJAVASSIST (MyBatis 版本为 3.3 及以上的)
vfsImpl指定 VFS 的实现类提供 VFS 类的全限定名,如果存在多个,可以使用逗号分隔Not set
useActualParamName允许用方法参数中声明的实际名称引用参数。要使用此功能,项目必须被编译为 Java 8 参数的选择。(从版本 3.4.1 开始可以使用)true|falsetrue

例如:

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <setting name="useGeneratedKeys" value="false"/>
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <setting name="defaultStatementTimeout" value="25"/>
    <setting name="defaultFetchSize" value="100"/>
    <setting name="safeRowBoundsEnabled" value="false"/>
    <setting name="mapUnderscoreToCamelCase" value="false"/>
    <setting name="localCacheScope" value="SESSION"/>
    <setting name="jdbcTypeForNull" value="OTHER"/>
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

5.3<typeAliases>标签

在mapper.xml中需要使用parameterType和resultType属性来配置SQL语句的输入参数类型和输出参数类型,类必须要写上全限定名,比如一个SQL的返回值映射为Student类,则resultType属性要写com.shenxm.mybatisdemo.po.User,这太长了,所以可以用别名来简化书写,比如

<typeAliases>
    <typeAlias type="com.shenxm.dao.UserEntity" alias="user"/>
</typeAliases>

之后就可以在resultType上直接写user,mybatis会根据别名配置自动找到对应的类。

另外,对于基本的Java类型 -> 8大基本类型以及包装类,以及String类型,mybatis提供了默认的别名,别名为其简单类名的小写,比如原本需要写java.lang.String,其实可以简写为string

5.4<typeHandlers>标签

用于处理Java类型和Jdbc类型之间的转换,mybatis有许多内置的TypeHandler,比如StringTypeHandler,会处理Java类型String和Jdbc类型CHAR和VARCHAR。

5.5<objectFactory>标签

mybatis会根据resultTyperesultMap的属性来将查询得到的结果封装成对应的Java类,它有一个默认的DefaultObjectFactory,用于创建对象实例。

5.6<plugins>标签

可以用来配置mybatis的插件,比如在开发中经常需要对查询结果进行分页,就需要用到pageHelper分页插件,这些插件就是通过这个标签进行配置的。在mybatis底层,运用了责任链模式+动态代理去实现插件的功能

<!-- PageHelper 分页插件 -->
<plugins>
  <plugin interceptor="com.github.pagehelper.PageInterceptor">
     <property name="helperDialect" value="mysql"/>
  </plugin>
</plugins>

5.7<environments>标签

用来配置数据源 , 可以通过配置多个 environment 标签来连接多个数据库,需要注意的是必须指定其中一个为默认运行环境(通过default指定)。

environment 标签提供了两个子标签,即 transactionManager 和 dataSource。

transactionManager标签: MyBatis 支持两个事务管理器,即 JDBC 和 MANAGED。

dataSource标签: 用于配置数据库的连接属性,例如要连接的数据库的驱动程序名称、URL、用户名和密码等。

5.8<mappers>标签

配置mapper.xml的扫描路径。

<!--     指定映射配置文件的位置 -->
    <mappers>
<!--        1.单独加载某个映射配置文件 -->
<!--        <mapper resource="com\shenxm\mybatisdemo\mapper\UserMapper.xml"/>-->
<!--     2.加载某包所有的配置文件  -->
        <package name="com.shenxm.mybatisdemo.mapper"/>
    </mappers>

六、 Mybatis的mapper(映射器)

6.1映射器概念

映射器: 是 MyBatis 中最重要的文件,文件中包含一组 SQL 语句(例如查询、添加、删除、修改),例如UserMapper.xml和UserMapper.java接口类就是一个映射器。

映射器由 Java 接口和 XML 文件(或注解)共同组成,它的作用如下:

  • 定义参数类型
  • 配置缓存
  • 提供 SQL 语句和动态 SQL
  • 定义查询结果和 POJO 的映射关系

映射器有以下两种实现方式:

  • 通过 XML 文件方式实现,比如我们在 mybatis-config.xml 文件中描述的 XML 文件,用来生成 mapper。(推荐使用)
  • 通过注解的方式实现,使用 Configuration 对象注册 Mapper 接口。

映射器可以定义以下标签:

元素名称描述备注
mapper映射文件的根节点,只有 namescape 一个属性namescape 作用如下:用于区分不同的 mapper,全局唯一绑定DAO接口,即面向接口编程。当 namescape 绑定某一接口后,可以不用写该接口的实现类,MyBatis 会通过接口的完整限定名查找到对应的 mapper 配置来执行 SQL 语句。因此 namescape 的命名必须要跟接口同名。
select查询语句,最常用、最复杂的元素之一可以自定义参数,返回结果集等
insert插入语句执行后返回一个整数,代表插入的条数
update更新语句执行后返回一个整数,代表更新的条数
delete删除语句执行后返回一个整数,代表删除的条数
parameterMap定义参数映射关系即将被删除的元素,不建议使用
sql允许定义一部分的 SQL,然后在各个地方引用它例如,一张表列名,我们可以一次定义,在多个 SQL 语句中使用
resultMap用来描述数据库结果集与对象的对应关系,它是最复杂、最强大的元素提供映射规则
cache配置给定命名空间的缓存-
cache-ref其它命名空间缓存配置的引用-

6.2Mybatis执行sql的两种方式

1.通过 SqlSession 发送 SQL。

2.通过 SqlSession 获取 Mapper 接口,通过 Mapper 接口发送 SQL。

//第一种:通过 SqlSession 发送 SQL。
List<User> users = (User)sqlSession.selectList("com.shenxm.mybatisdemo.mapper.UserMapper.selectAll");
//第二种:通过 SqlSession 获取 Mapper 接口,通过 Mapper 接口发送 SQL。
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 users = mapper.selectAll();

6.3select标签

用于执行查询操作。

执行 SQL 语句时可以定义参数 :基本参数类型或者复杂参数类型,例如JavaBean,Map等。

Mybatis提供了强大的 映射规则,执行sql后,会将结果集自动映射到JavaBean中。 通常这种映射采用Java驼峰命名规则。

参数的传递使用#{参数名},相当于告诉 MyBatis 生成 PreparedStatement 参数。对于 JDBC,该参数会被标识为“?”。

传递参数的四种方式:

  1. 基本类型传参
  2. 使用Map传参
  3. 使用注解传参: @Param() 传递参数
  4. 使用JavaBean传参

代码实现:

UserMapper接口:

package com.shenxm.mybatisdemo.mapper;

import com.shenxm.mybatisdemo.po.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;
/**
 * @Author: shen
 * @CreateTime: 2022-01-05  21:48
 * @Description: UserMapper
 * @Version 1.0
 */
public interface UserMapper {

    List<User> selectAll();

    String getNameById(@Param("id") Long id);

    List<User> selectByMap(Map<String, Object> param);

    List<User> selectByentity(User user);
}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.shenxm.mybatisdemo.mapper.UserMapper">
<!--    resultMap
	id 在命名空间中唯一的标识符
	type 结果集映射的javabean 或者 泛型为该类型的集合
-->
    <resultMap id="userMap" type="com.shenxm.mybatisdemo.po.User">
<!--    id主键映射
        result 非主键映射
        property javabean 中的 filed
		column datatable 中的 filed  -->
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <result property="email" column="email"/>
    </resultMap>

<!--    <select id="selectAll" resultType="com.shenxm.mybatisdemo.po.User">-->
<!--        SELECT * FROM user;-->
<!--    </select>-->

    <select id="selectAll" resultMap="userMap">
        SELECT * FROM user;
    </select>

    <select id="getNameById" resultType="string">
        SELECT name FROM user where id = #{id};
    </select>

    <select id="selectByMap" parameterType="map" resultType="com.shenxm.mybatisdemo.po.User">
        SELECT * FROM user where id = #{id};
    </select>

    <select id="selectByentity" parameterType="com.shenxm.mybatisdemo.po.User" resultType="com.shenxm.mybatisdemo.po.User">
        SELECT * FROM user where id = #{id};
    </select>

</mapper>

DemoTest:

 @Test
    public void testMapper2() {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";

        Reader config = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            // 1.加载配置文件
            // 第一种: Resources.getResourceAsReader(resource);
            config = Resources.getResourceAsReader(resource);
            // 第二种:InputStream config = Resources.getResourceAsStream(resource);
            // 2.构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
            // 3.打开SqlSession连接
            sqlSession = sqlSessionFactory.openSession();
            // 4.获取该接口的代理对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 5.执行接口中的方法
            System.out.println("=================查询所有数据=========================");
            //查询所有数据
            List<User> userList = mapper.selectAll();
            userList.forEach(System.out::println);
            System.out.println("=================基本数据类型传参==================");
            //基本数据类型传参
            String users = mapper.getNameById(1L);
            System.out.println("基本数据类型传参:" + users);
            System.out.println("=================map传参==================");
            //map传参
            HashMap<String, Object> map = new HashMap<>();
            map.put("id", 1L);
            List<User> userList1 = mapper.selectByMap(map);
            userList1.forEach(System.out::println);
            System.out.println("================JavaBean传参==================");
            //JavaBean传参
            User user = new User();
            user.setId(1L);
            List<User> userList2 = mapper.selectByentity(user);
            userList2.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.释放SqlSession资源
            sqlSession.close();
        }
    }

常用标签属性:

属性名称描 述备注
id它和 Mapper 的命名空间组合起来使用,是唯一标识符,供 MyBatis 调用如果命名空间+id不唯一,那么 MyBatis 抛出异常
parameterType表示传入 SQL 语句传入参数类型的全限定名或别名。它是一个可选属性,MyBatis 能推断出具体传入语句的参数支持基本数据类型和 JavaBean、Map 等复杂数据类型
resultTypeSQL 语句执行后返回的类型(全限定名或者别名)。如果是集合类型,返回的是集合元素的类型,返回时可以使用 resultType 或 resultMap 之一-
resultMap它是映射集的引用,与 元素一起使用,返回时可以使用 resultType 或 resultMap 之一是 MyBatis 最复杂的元素,可以配置映射规则、级联、typeHandler 等
flushCache用于设置在调用 SQL 语句后是否要求 MyBatis 清空之前查询的本地缓存和二级缓存默认值为 false,如果设置为 true,则任何时候只要 SQL 语句被调用都将清空本地缓存和二级缓存
useCache启动二级缓存的开关,默认值为 true,表示将査询结果存入二级缓存中-
timeout用于设置超时参数,单位是秒(s),超时将抛出异常-
fetchSize获取记录的总条数设定默认值是数据库厂商提供的 JDBC 驱动所设置的条数
statementType告诉 MyBatis 使用哪个 JDBC 的 Statement 工作,取值为 STATEMENT(Statement)、 PREPARED(PreparedStatement)、CALLABLE(CallableStatement)-
resultSetType这是针对 JDBC 的 ResultSet 接口而言,其值可设置为 FORWARD_ONLY(只允许向前访问)、SCROLL_SENSITIVE(双向滚动,但不及时更新)、SCROLLJNSENSITIVE(双向滚动,及时更新)-

6.4insert标签

用来定义插入语句,执行插入操作。 当 MyBatis 执行完一条插入语句后,就会返回其影响数据库的行数。

传递参数的四种方式:

  1. 基本类型传参
  2. 使用Map传参
  3. 使用注解传参: @Param() 传递参数
  4. 使用JavaBean传参

主键回填: 数据库自动生成的主键回填到请求对象,供业务使用, 此时,我们就可以通过在 insert 标签中添加 keyProperty 和 useGeneratedKeys 属性,来实现该功能。

UserMapper接口:

package com.shenxm.mybatisdemo.mapper;

import com.shenxm.mybatisdemo.po.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;
/**
 * @Author: shen
 * @CreateTime: 2022-01-05  21:48
 * @Description: UserMapper
 * @Version 1.0
 */
public interface UserMapper {

    List<User> selectAll();

    String getNameById(@Param("id") Long id);

    List<User> selectByMap(Map<String, Object> param);

    List<User> selectByentity(User user);

    int addUser(@Param("user") User user);

}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.shenxm.mybatisdemo.mapper.UserMapper">

    <insert id="addUser" keyProperty="id" useGeneratedKeys="true">
        INSERT INTO user (name,age,email)
        VALUES(#{user.name},#{user.age},#{user.email})
    </insert>

</mapper>

DemoTest:

 @Test
    public void testMapper3() {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";

        Reader config = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            // 1.加载配置文件
            // 第一种: Resources.getResourceAsReader(resource);
            config = Resources.getResourceAsReader(resource);
            // 第二种:InputStream config = Resources.getResourceAsStream(resource);
            // 2.构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
            // 3.打开SqlSession连接
            sqlSession = sqlSessionFactory.openSession();
            // 4.获取该接口的代理对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 5.执行接口中的方法
            System.out.println("================插入==================");
            User user = new User();
            user.setAge(22);
            user.setName("xiaowu");
            user.setEmail("xiaowu@baomidou.com");
            int i = mapper.addUser(user);
            sqlSession.commit();//提交
            System.out.println("成功插入了:" + i + "条");
            System.out.println("主键回填对象:" + user.getId());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.释放SqlSession资源
            sqlSession.close();
        }
    }

常用属性:

属性名称描述备注
id它和 Mapper 的命名空间组合起来使用,是唯一标识符,供 MyBatis 调用如果命名空间+ id 不唯一,那么 MyBatis 抛出异常
parameterType传入 SQL 语句的参数类型的全限定名或别名,它是一个可选属性。支持基本数据类型和 JavaBean、Map 等复杂数据类型
keyProperty该属性的作用是将插入操作的返回值赋给 PO 类的某个属性,通常为主键对应的属性。如果是联合主键,可以将多个值用逗号隔开。-
useGeneratedKe该属性用来设置,是否使用 JDBC 提供的 getGenereatedKeys() 方法,获取数据库内部产生的主键并赋值到 keyProperty 属性设置的请求对象的属性中,例如 MySQL、SQL Server 等自动递增的字段,其默认值为 false。该属性值设置为 true 后,会将数据库生成的主键回填到请求对象中,以供其他业务使用。
flushCache该属性用于设置执行该操作后,是否会清空二级缓存和本地缓存,默认值为 true。-
timeout该属性用于设置执行该操作的最大时限,如果超时,就抛异常。-
databaseId取值范围 oracle、mysql 等,表示数据库厂家;元素内部可通过 来为特定数据库指定不同的 sql 语句。MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。
keyColumn该属性用于设置第几列是主键,当主键列不是表中的第 1 列时,就需要设置该属性。如果是联合主键,可以将多个值用逗号隔开。-

6.5update标签

用于定义更新语句,执行更新操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。

传递参数的四种方式:

  1. 基本类型传参
  2. 使用Map传参
  3. 使用注解传参: @Param() 传递参数
  4. 使用JavaBean传参

UserMapper接口:

int updateByentity(@Param("user") User user);

UserMapper.xml:

  <update id="updateByentity">
        UPDATE user SET age=#{user.age}  WHERE id = #{user.id}
  </update>

DemoTest:

  @Test
    public void testMapper4() {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";

        Reader config = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            // 1.加载配置文件
            // 第一种: Resources.getResourceAsReader(resource);
            config = Resources.getResourceAsReader(resource);
            // 第二种:InputStream config = Resources.getResourceAsStream(resource);
            // 2.构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
            // 3.打开SqlSession连接
            sqlSession = sqlSessionFactory.openSession();
            // 4.获取该接口的代理对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 5.执行接口中的方法
            System.out.println("================更新==================");
            User user = new User();
            user.setAge(18);
            user.setId(8L);
            int i = mapper.updateByentity(user);
            sqlSession.commit();//提交
            System.out.println("共更新了 " + i + " 条记录");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.释放SqlSession资源
            sqlSession.close();
        }
    }

常用属性:

属性名称描述备注
id它和 Mapper 的命名空间组合起来使用,是唯一标识符,供 MyBatis 调用如果命名空间+ id 不唯一,那么 MyBatis 抛出异常
parameterType传入 SQL 语句的参数类型的全限定名或别名,它是一个可选属性。支持基本数据类型和 JavaBean、Map 等复杂数据类型
flushCache该属性用于设置执行该操作后,是否会清空二级缓存和本地缓存,默认值为 true。-
timeout该属性用于设置 SQL 执行的超时时间,如果超时,就抛异常。-
statementType执行 SQL 时使用的 statement 类型, 默认为 PREPARED,可选值:STATEMENT,PREPARED 和 CALLABLE。-

注意:update 标签中没有 resultType 属性,只有查询操作才需要对返回结果类型进行相应的指定。

6.6delete标签

定义 delete 语句,执行删除操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。

传递参数的四种方式:

  1. 基本类型传参
  2. 使用Map传参
  3. 使用注解传参: @Param() 传递参数
  4. 使用JavaBean传参

UserMapper接口:

int deleteById(@Param("id") Long id);

UserMapper.xml:

 <delete id="deleteById">
        DELETE FROM `user` WHERE id = #{id}
 </delete>

DemoTest:

@Test
    public void testMapper5() {
        // 核心配置文件classpath路径
        String resource = "mybatis/mybatis-config.xml";

        Reader config = null;
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        try {
            // 1.加载配置文件
            // 第一种: Resources.getResourceAsReader(resource);
            config = Resources.getResourceAsReader(resource);
            // 第二种:InputStream config = Resources.getResourceAsStream(resource);
            // 2.构建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
            // 3.打开SqlSession连接
            sqlSession = sqlSessionFactory.openSession();
            // 4.获取该接口的代理对象
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 5.执行接口中的方法
            System.out.println("================删除==================");
            int i = mapper.deleteById(8L);
            sqlSession.commit();//提交
            System.out.println("删除了 " + i + " 条记录");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.释放SqlSession资源
            sqlSession.close();
        }
    }

常用属性:

属性名称描述备注
id它和 Mapper 的命名空间组合起来使用,是唯一标识符,供 MyBatis 调用如果命名空间+ id 不唯一,那么 MyBatis 抛出异常
parameterType传入 SQL 语句的参数类型的全限定名或别名,它是一个可选属性。支持基本数据类型和 JavaBean、Map 等复杂数据类型
flushCache该属性用于设置执行该操作后,是否会清空二级缓存和本地缓存,默认值为 true。-
timeout该属性用于设置 SQL 执行的超时时间,如果超时,就抛异常。-
statementType执行 SQL 时使用的 statement 类型, 默认为 PREPARED,可选值:STATEMENT,PREPARED 和 CALLABLE。-

注意: delete 标签中没有 resultType 属性,只有查询操作才需要对返回结果类型进行相应的指定。

6.7resultMap标签

主要用于解决实体类属性名与数据库表中字段名不一致的情况,可以将查询结果映射成实体对象。

注意:MyBatis 版本只支持 resultMap 查询,不支持更新或者保存,更不必说级联的更新、删除和修改。

<resultMap id="" type="">
    <constructor><!-- 类再实例化时用来注入结果到构造方法 -->
        <idArg/><!-- ID参数,结果为ID -->
        <arg/><!-- 注入到构造方法的一个普通结果 --> 
    </constructor>
    <id/><!-- 用于表示哪个列是主键 -->
    <result/><!-- 注入到字段或JavaBean属性的普通结果 -->
    <association property=""/><!-- 用于一对一关联 -->
    <collection property=""/><!-- 用于一对多、多对多关联 -->
    <discriminator javaType=""><!-- 使用结果值来决定使用哪个结果映射 -->
        <case value=""/><!-- 基于某些值的结果映射 -->
    </discriminator>
</resultMap>

其中:

  • 元素的 type 属性表示需要的 POJO,id 属性是 resultMap 的唯一标识。
  • 子元素

    id 和 result 元素都有以下属性。

    元素说明
    property映射到列结果的字段或属性。如果 POJO 的属性和 SQL 列名(column元素)是相同的,那么 MyBatis 就会映射到 POJO 上
    column对应 SQL 列
    javaType配置 Java 类型。可以是特定的类完全限定名或 MyBatis 上下文的别名
    jdbcType配置数据库类型。这是 JDBC 类型,MyBatis 已经为我们做了限定,基本支持所有常用数据库类型
    typeHandler类型处理器。允许你用特定的处理器来覆盖 MyBatis 默认的处理器。需要指定 jdbcType 和 javaType 相互转化的规则

    一条 SQL 查询语句执行后会返回结果集,结果集有两种存储方式,即使用 Map 存储和使用 POJO 存储。

    6.8where标签

    条件标签

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace=绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.shenxm.dao.IUserMapper">
        <!--通用返回结果集 -->
        <resultMap id="baseResultMap" type="com.shenxm.entity.UserEntity">
            <id property="userId" column="user_id"></id>
            <result property="userName" column="user_name"></result>
            <result property="status" column="status"></result>
        </resultMap>
        
        <select id="queryUserByid" resultMap="baseResultMap">
            select * from user
            <where>
                <!--自动删除多余的and -->
                and  user_id=#{userId}
                <if test="userName != null and userName != ''" >
                    <!--使用bind标签,设置格式,自动拼接通配符 -->
                    <bind name="userName" value="'%' + userName +'%'"></bind>
                    and userName like #{userName}
                </if>
            </where>
        </select>
    </mapper>
    

    6.9sql标签

    复用标签

    <sql id="insert_set_column">
    	<!-- suffixOverrides属性,会自动把多余的“,”删除 -->
    	<trim prefix="(" suffix=")" suffixOverrides=",">
    		empno,
    		<if test="userName != null">user_name,</if>
    		<if test="status != null">status,</if>
    	</trim>
    </sql>
    

    6.10foreach标签

    用来遍历的标签

    <!--相当于select * from User where user_id in (1,2,3...)) -->
    <select id="selectByIds" parameterType="list" resultMap="baseResultMap">
    	select * from User
    	<where>
    		<foreach item="id" collection="list" open="id IN(" close=")" separator=",">
    			#{id}
    		</foreach>
    	</where>
    </select>
    
    属性名说明
    item表示集合中每一个元素进行迭代时的别名
    collection表示传入的参数,可能是list、array、map
    index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,
    open表示该语句以什么开始,
    separator表示在每次进行迭代之间以什么符号作为分隔 符,
    close表示以什么结束。

    6.11choose标签

    多条件分支判断

    <select id="findByCondition" resultType="baseResultMap">
            select * from user where 1=1
            <choose>
                 <when test="status !=null and status !='' ">
                     and  status=#{status}
                 </when>
                <when test="userName !=null and userName !='' ">
                    and  user_Name=#{userName}
                </when>
                <otherwise>
                    and user_id= 1
                </otherwise>
            </choose>
    </select>
    

    七、高级用法

    7.1联表查询

    例子:根据id查询学生信息并包括该学生所在的班级信息。

    select * from tb_stu s join tb_class c on s.class_id=c.cid where stu_id= ?
    

    mapper.xml:

     <resultMap id="all" type="com.lrs.entity.Student">
            <id column="stu_id" property="id"/>
            <result column="stu_name" property="name"/>
            <result column="stu_age" property="age"/>
            <result column="c_id" property="cid"/>
            <association property="aClass" javaType="com.lrs.entity.AClass">
                <id column="cid" property="cid"/>
                <result column="cname" property="cname"/>
            </association>
        </resultMap>
        <sql id="allClass">
            stu_id,stu_name,stu_age,s.cid c_id,c.cid,cname
        </sql>
        <select id="selectClassById" resultMap="all">
            select <include refid="allClass"/> from student s join class c on s.cid = c.cid where stu_id=#{id}
        </select>
    

    7.2分页查询pageHelper

    可以用分页插件来帮我们快速实现分页查询操作,分页查询的sql语句:

    -- page代表你想要查询的页码数,pageSize代表你想要每页显示的数据个数。
    select * from user [where条件] limit (page-1)*pageSize,pageSize
    
    1. 引入maven依赖
    <!--引入pageHelper-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.11</version>
    </dependency>
    
    1. 在mybatis-config.xml中设置pageHelper的拦截器(写在mybatis中得configuration标签内)
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    
    1. 使用

    我们可以在测试里使用,未来就相当于在servlet层中使用。我们分页查询出来的内容记得要封装到pageInfo类中,因为pageInfo类中有get方法,可以调用出我们想要的数据。

    package com.shenxm;
    
    import com.github.pagehelper.PageInfo;
    import com.shenxm.dao.IUserMapper;
    import com.shenxm.entity.UserEntity;
    import com.shenxm.utils.MybatisUtils;
    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 org.junit.Test;
    
    import java.io.IOException;
    import java.io.Reader;
    import java.util.List;
    
    public class DemoTest {
        @Test
        public void test3() throws IOException {
            SqlSession sqlSession = null;
            sqlSession = MybatisUtils.getSqlSession();
            System.out.println("sqlSession.getConnection()是:"+sqlSession.getConnection());
            IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
            List<UserEntity> users = mapper.queryAll();
            //封装到PageInfo类中
            PageInfo<UserEntity> userPageInfo = new PageInfo<UserEntity>(users);
            //getTotal():获取表中数据的总个数
            //getPages():获取总页数
            //getPageSize():获取当前页查询到的数据的个数
            //getList():获取当前页码对应的数据
            long total = userPageInfo.getTotal();
            System.out.println("表中一共有"+total+"条数据");
            System.out.println(users);
            // 归还连接给数据源
            sqlSession.close();
        }
    }
    

    分页拦截器原理:

    ​ 在我们使用了pageHelper以后,他会在我们执行查询数据库的方法之前,先在sql语句中拼接上我们limit分页关键字以及后面跟的数据,然后再执行查询。

    7.3代码生成generator

    generator可以帮我们快速生成实体类,dao和xml映射文件,帮我们实现简单的增删改查功能。

    mybatis-generator 官网: http://mybatis.org/generator/

    1. 引入maven依赖
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    
    1. generator的配置文件

    必须与pom.xml同级目录。

    代码如下:直接复制即可。(设置file名为generatorConfig.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    
    <generatorConfiguration>
        <!--找到你的mysql驱动jar的位置-->
        <classPathEntry location="F:\apache-maven-3.9.0\repository\com\mysql\mysql-connector-j\8.0.32" />
        <context id="DB2Tables" targetRuntime="MyBatis3">
            <!-- 去除页面代码注释  -->
            <commentGenerator>
                <property name="suppressAllComments" value="true" />
            </commentGenerator>
            <!--数据源的配置信息-->
            <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                            connectionURL="jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghai"
                            userId="root"
                            password="123456">
            </jdbcConnection>
    
            <javaTypeResolver >
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
    
            <!--java实体类的配置-->
            <javaModelGenerator targetPackage="com.shenxm.entity" targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true" />
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
    
            <!--映射文件的配置-->
            <sqlMapGenerator targetPackage="mapper"  targetProject=".\src\main\resources">
                <property name="enableSubPackages" value="true" />
            </sqlMapGenerator>
    
            <!--dao数据访问层的配置-->
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.shenxm.dao"  targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true" />
            </javaClientGenerator>
    
            <!--数据库表和实体的映射关系
                  schema:数据库名称
                  tableName: 表名
                  domainObjectName:实体类名
                  enableUpdateByExample:是否生成复杂的修改操作
            -->
            <table schema="mybatis" tableName="user" domainObjectName="User"
                   enableUpdateByExample="false" enableSelectByExample="false" enableDeleteByExample="false" enableCountByExample="false">
            </table>
        </context>
    </generatorConfiguration>	
    
    1. 运行配置
    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);
    

    八、Mybatis的缓存

    8.1缓存的概念

    缓存就是存在与内存中的临时数据。

    mysql数据库中的数据存在表中,表中的数据存在我们电脑的磁盘里,所以我们就算关掉数据库,关掉电脑,我们数据库中的数据也会存在。

    使用缓存可以减少和数据库之间的交互次数,提高代码的执行效率。可以理解为我们电脑的内存,固态,机械硬盘,缓存可以相当于内存,那么效率孰高孰低一目了然。

    8.2缓存的查询

    如果是第一次执行查询该数据,那么会先查询数据库,并把查询的结果放到缓存中,以后可以直接从缓存中获取数据,从而减少对数据库的访问频率。之后再查询的时候,程序会先看缓存中是否有目标数据,如果有直接在缓存中获取结果,如果没有那么还会在数据库中查询。

    缓存中适合放入的数据:

    (1)经常查询,且不回经常改变的数据。

    (2)数据的正确与否对最终影响结果不大的。

    缓存中不适合放入的数据:

    (1)经常改变的数据

    (2)数据的正确与否对最终结果影响很大的。即对数据安全性要求很高。

    例如:商品的库存,银行的汇率,股市的牌价。

    8.3缓存的分类

    mybatis支持两种:

    1. 缓存一级缓存:基于SqlSession级别的缓存。默认一级缓存是开启的,不能关闭。

    2. 二级缓存:基于SqlSessionFactory级别的缓存,它可以做到多个SqlSession共享数据。默认它是关闭。需要手动开启。

    mybatis查询的顺序:

    二级缓存→一级缓存→数据库。

    如果二级缓存没有命中,就去一级缓存中查询,一级缓存中也没有命中,就在数据库中查询。

    8.4一级缓存的开启

    一级缓存默认是开启。

     @Test
        public void test4() throws IOException {
            SqlSession sqlSession = null;
            sqlSession = MybatisUtils.getSqlSession();
            System.out.println("sqlSession.getConnection()是:"+sqlSession.getConnection());
            IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);
    
            PageHelper.startPage(1,3);
            List<UserEntity> users = mapper.queryAll();
            System.out.println(users);
            List<UserEntity> users1 = mapper.queryAll();
            System.out.println(users1);
            // 归还连接给数据源
            sqlSession.close();
        }
    

    当我们查询同一个数据时,sql语句只执行了一次,第二次查询的时候就没有再去数据库中执行查询了。

    如果缓存中没有这个数据,那么它就会在数据库中执行查询,然后把查询的结果存到缓存中。

    注意: 必须是在同一个sqlSession中执行,否则还是会在数据库中查询。

    8.5二级缓存的开启

    二级缓存默认是关闭的,需要我们手动开启。

    1. mybatis-config.xml中加入如下代码,注意放入的位置。
    <settings>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
    1. mapper.xml下使用二级缓存。只需加入一句:<cache>
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace=绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.shenxm.dao.IUserMapper">
        <cache></cache>
    <!--...... -->
    </mapper>
    
    1. 实体类中实现序列化接口

    二级缓存实际底层的原理时HashMap,调用缓存就相当于进行IO操作。

    在java中,对java对象进行IO操作时,需要让类实现序列化(实现Serializable接口)。

    1. 测试
     @Test
        public void testSlectById() throws Exception{
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
            SqlSession session = factory.openSession();
            UserMapper mapper = session.getMapper(IUserMapper.class);
            User user = mapper.selectByPrimaryKey(2);
            System.out.println(user);
            session.close();
            SqlSession session1 = factory.openSession();
            UserMapper mapper1 = session1.getMapper(IUserMapper.class);
            User user1 = mapper1.selectByPrimaryKey(2);
            System.out.println(user1);
        }
    
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值