Spring学习笔记之MyBatis

本文详细介绍了MyBatis的基础、进阶和常用技巧,包括MyBatis与Hibernate对比、SQL配置、ORM操作、逆向工程、缓存与动态SQL,助您快速上手Spring与MyBatis开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系列文章目录

Spring学习笔记 之 Springhttps://blog.youkuaiyun.com/weixin_43985478/article/details/124411746?spm=1001.2014.3001.5501

Spring学习笔记 之 Spring-MVChttps://blog.youkuaiyun.com/weixin_43985478/article/details/124923196?spm=1001.2014.3001.5501


目录


一、MyBatis

主流的ORM(对象关系映射)框架,之前叫做 iBatis,后来更名为 MyBatis,实现数据持久化的框架同时 Java.NETRuby 三种语⾔,MyBatis 是⼀个对 JDBC 进⾏封装的框架

MyBatis Hibernate的区别?

  • Hibernate 是⼀个全⾃动化” ORM 框架,MyBatis 是⼀个半⾃动化的”ORM框架
  • 全⾃动化:开发者只需要调⽤相关接⼝就可以完成操作,整个流程框架都已经进⾏了封装
  • Hibernate 实现了 POJO 和数据库表之间的映射,同时可以⾃动⽣成 SQL 语句并完成执⾏
  • 半⾃动化:框架只提供⼀部分功能,剩下的⼯作仍需要开发者⼿动完成,MyBatis 没有提供 POJO 与数据库表的映射,只实现了 POJO SQL 之间的映射关系,需要开发者⾃定义 SQL 语句,以及数据与POJO 之间的装配关系
  • 半⾃动化的⽅式提⾼了框架的灵活性,开发者可以根据具体的业务需求,完成定制化的持久层解决⽅案
  • MyBatis 对所有的 JDBC 进⾏了封装,包括参数设置、SQL 执⾏、结果集解析等,通过 XML 配置/注解的⽅式完成 POJO 与数据的映射

MyBatis的优点

  • 极⼤简化了 JDBC 代码的开发
  • 简单好⽤、容易上⼿、具有更好的灵活性
  • 通过将 SQL 定义在 XML 中的⽅式降低程序的耦合性
  • ⽀持动态 SQL,可以根据具体业务需求灵活实现功能

MyBatis的缺点

  • 相⽐于 Hibernate,开发者需要完成更多⼯作,⽐如定义 SQL、设置 POJO 与数据的映射关系等
  • 要求开发⼈员具备⼀定的 SQL 编写能⼒,在⼀些特定场景下⼯作量⽐较⼤
  • 数据库移植性差,以为 SQL 依赖于底层数据库,如果要进⾏数据库迁移,部分 SQL 需要重写编
使⽤ MyBatis 进⾏开发,主要完成两步操作:
  • ⾃⼰编写 SQL
  • ⾃⼰完成数据库数据与 POJO 的映射

二、MyBatis ⼊⻔

1、创建 Maven ⼯程,pom.xml 引⼊相关依赖

 <dependencies>
        <!--MyBatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>
</dependencies>

2、创建实体类

import lombok.Data;

/**
 * @Author 苦恼的java小宝
 * @Date 2022/6/17 12:11
 * @ClassName: People
 * @Version 1.0
 */

@Data
public class People {
    private Integer id;
    private String name;
    private Double money;
}

3、配置 MyBatis 环境,在 resources 路径下创建 confifig.xml(⽂件名可以⾃定义),配置数据源信息

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

<configuration>
    <!-- 配置 MyBatis 运⾏环境 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <!-- 数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--连接本地sql服务的test库-->
                <property name="url" value="jdbc:mysql://localhost:3306/test?
                    useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
4MyBatis 开发有两种⽅式
  • 使⽤原⽣接⼝
  • Mapper 代理实现⾃定义接⼝

使用原生接口

1、在mapper包中创建 Mapper ⽂件 PeopleMapper.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.hqq.mapper.PeopleMapper">

    <select id="findById" parameterType="java.lang.Integer" resultType="com.hqq.entity.People">
        select * from people where id = #{id};
    </select>

</mapper>
  • namespace 设置为PeopleMapper.xml⽂件所在包名 + ⽂件名
  • parameterType 是参数数据类型
  • resultType 是返回值数据类型

2、在全局配置⽂件 confifig.xml 中注册 PeopleMapper.xml

    <!--注册Mapper-->
    <mappers>

        <!--这里要用斜/,而不是用点.-->
        <mapper resource="com/hqq/mapper/PeopleMapper.xml"></mapper>

    </mappers>

3、调⽤ API 完成操作

public class Test {
    public static void main(String[] args) {
        //加载MyBatis配置文件
        InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(inputStream);

        //获取SqlSession
        SqlSession sqlSession = sessionFactory.openSession();
        //调用MyBatis原生接口执行SQL语句
        String statement = "com.hqq.mapper.PeopleMapper.findById";
        People people = sqlSession.selectOne(statement);

        System.out.println(people);
        sqlSession.close();
    }
}

4IDEA 中⽆法直接读取 非resources 路径下的 XML ⽂件,需要进⾏设置,pom.xml

    <build>
        <resources>
            <resource>

                <directory>src/main/java</directory>
                <includes>
                    <!--**/*.xml,表示所有路径下的所有xml文件-->
                    <include>**/*.xml</include>
                </includes>

            </resource>
        </resources>
    </build>

Mapper 代理实现⾃定义接⼝

开发者只需要定义接⼝,并不需要实现接⼝,具体的实现⼯作由 Mapper 代理结合配置⽂件完成

1.自定义PeoPleRepository接口

public interface PeopleRepository {

    //增删改查
    public int save(People people);
    public int deleteById(Integer id);
    public int update(People people);
    public People findById(Integer id);
    public List<People> FindAll();
}
2、创建 PeopleRepository.xml,定义接⼝⽅法对应的 SQL 语句

MyBatis 会⾃动根据规则创建 PeopeleRepository 接⼝的 实现类代理对象

规则如下:
  • PeopleMapper.xml 中的 namespace 为PeoPleRepository接⼝的全限定类名
  • PeopleMapper.xml 中的 statement id 为接⼝中对应的⽅法名
  • statement可分为insert、delete、update、select
  • PeopleMapper.xml 中的 parameterType 和接⼝中对应⽅法的参数类型⼀致
  • PeopleMapper.xml 中的 resultType 和接⼝中对应⽅法的返回值类型⼀致
<?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.hqq.repository.PeopleRepository">
    <!--增-->
    <insert id="save" parameterType="com.hqq.entity.People">
        insert into people(name,money) values(#{name},#{money})
     </insert>

    <!--删-->
    <delete id="deleteById" parameterType="java.lang.Integer">
        delete from people where id = #{id}
     </delete>

    <!--改-->
    <update id="update" parameterType="com.hqq.entity.People">
        update people set name = #{name},money = #{money} where id = #{id}
     </update>

    <!--查-->
    <select id="findById" parameterType="java.lang.Integer" resultType="com.hqq.entity.People">
        select * from people where id = #{id}
     </select>

    <select id="findAll" resultType="com.hqq.entity.People">
        select * from people
 </select>

</mapper>

3、config.xml完成注册

    <!--注册Mapper-->
    <mappers>
        <mapper resource="com/hqq/repository/PeopleRepository.xml"></mapper>
    </mappers>

4、调⽤API

public class Test {
    public static void main(String[] args) {
        //加载MyBatis配置文件
        InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(inputStream);

        //获取SqlSession
        SqlSession sqlSession = sessionFactory.openSession();

        //获取实现了自定义接口的代理对象
        PeopleRepository peopleRepository = sqlSession.getMapper(PeopleRepository.class);

        System.out.println("-------------执行前---------------");
        //执行前
        List<People> list1 = peopleRepository.findAll();
        for(People p :list1){
            System.out.println(p);
        }


        //增
        People p1 = new People(4,"大聪明",5.5);
        peopleRepository.save(p1);

        //删
        peopleRepository.deleteById(1);

        //改
        People p2 = new People(2,"李逍遥",888.8);
        peopleRepository.update(p2);

        //查
        //System.out.println(peopleRepository.findById(2));

        System.out.println("---------------执行后----------------");
        List<People> list2 = peopleRepository.findAll();
        for(People p :list2){
            System.out.println(p);
        }


        sqlSession.close();
    }
}

结果:

Mapper.xml 常⽤配置

MyBatis 配置⽂件有两种:
  • 全局环境配置⽂件(数据源、事务管理、Mapper 注册、打印 SQL、惰性加载、⼆级缓存)
  • Mapper 配置⽂件(定义⾃定义接⼝的具体实现⽅案:SQL、数据与 POJO 的映射)

三、单表查询

<select id="findById" parameterType="java.lang.Integer"
    resultType="com.hqq.entity.People">

     select * from people where id = #{id}

</select>
  • 业务:通过 id 查询 People 对象
  • ⽬标表:test/people
  • 实体类:com.hqq.entity.People
  • Mapper.xml 设置相关配置逻辑,由 MyBatis ⾃动完成查询,⽣成 POJO
  • statement 标签主要属性有 idparameterTyperesultType
  • id 对应接⼝的⽅法名,parameterType 定义参数的数据类型、resultType 定义查询结果的数据类型 (实体类的成员变量列表必须与⽬标表的字段列表⼀致)

paramterType

⽀持基本数据类型、包装类、String、多参数、POJO

1、基本数据类型,通过 id 查询 POJO

//接口方法
public People findById(int id);

//配置信息
<select id="findById" parameterType="int"
resultType="com.hqq.entity.People">
 select * from people where id = #{num}
</select>

2、包装类

//接口方法
public People findById(Integer id);

//配置信息
<select id ="findById" parameterType="int" resultType ="com.hqq.entity.People">
    select * from people where id = #{num}
</select>

3、String类型

//接口方法
public People findByName(String name);

//配置信息
<select id="findByName" parameterType="java.lang.String"
resultType="com.hqq.entity.People">
 select * from people where name = #{name}
</select>

4、多参数

//接口方法
public People findByIdAndName(Integer id,String name);

//配置信息
<select id="findByIdAndName" resultType="com.hqq.entity.People">
     select * from people where id = #{id} and name = #{name}
</select>

5、POJO

//接口方法
public int update(People people);

//配置信息
<update id="update" parameterType="com.hqq.entity.People">
     update people set name = #{name},money = #{money} where id = #{id}
</update>

resultType

resultType parameterType 的使⽤基本⼀致

四、多表关联查询

实际开发中最常⽤的是:⼀对多和多对多

⼀对多

1、建表

create table `t_classes`(
     `id` int(11) NOT NULL primary key auto_increment,
     `name` varchar(11) default null
);

create table `t_student`(
     `id` int(11) not null primary key auto_increment,
     `name` varchar(11) default null,
     `cid` int(11) default null,
     key `cid` (`cid`),
     constraint `t_student_ibfk_1` foreign key (`cid`) references `t_classes`(`id`)
)

2SQL

select s.id sid,s.name sname,c.id cid,c.name cname 
from t_student s,t_classes c 
where s.id = 1 and s.cid = c.id

3、创建实体类

//学生类
@Data
public class Student {
    private Integer id;
    private String name;
    private Classes classes;
}

//教室类
@Data
public class Classes {
    private Integer id;
    private String name;
    private List<Student> students;
}

4StudentRepository

public interface StudentRepository {
     public Student findById(Integer id);
}

5、StudentRepository.xml

  • resultType 直接将结果集与实体类进行映射
  • resultMap可以对接过进行二次封装,根据需求映射
  • id 表示主键
  • result 表示其他属性
<?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.hqq.repository.StudentRepository">

    <resultMap id="studentMap" type="com.hqq.entity.Student">

            <id column="sid" property="id"></id>
            <result column="sname" property="name"></result>

            <association property="classes" javaType="com.hqq.entity.Classes">
                <id column="cid" property="id" ></id>
                <result column="cname" property="name" ></result>
            </association>
    </resultMap>

    <select id="findById" parameterType="java.lang.Integer" resultMap="studentMap">
        select s.id sid,s.name sname,c.id cid,c.name cname
        from t_student s,t_classes c
        where s.id = #{id} and s.cid = c.id
    </select>
</mapper>

6、ClassesRepository

public interface ClassesRepository {
     public Classes findById(Integer id);
}

7、ClassesRepository.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.hqq.repository.ClassesRepository">

    <resultMap id="classesMap" type="com.hqq.entity.Classes">

        <id property="id" column="cid"></id>
        <result property="name" column="cname"></result>

        <collection property="students" ofType="com.hqq.entity.Student">
            <id property="id" column="sid"></id>
            <result property="name" column="sname"></result>
        </collection>

    </resultMap>

    <select id="findById" parameterType="java.lang.Integer" resultMap="classMap">
        select c.id cid,c.name cname,s.id sid,s.name sname 
        from t_classes c,t_student s 
        where c.id = #{id} and c.id = s.cid
    </select>
</mapper>

collection association 的区别

  • collection 是将结果集封装成⼀个集合对象(多个⽬标对象)
  • association 是将结果集封装成⼀个实体类的对象(⼀个⽬标对象)
  • collection 是通过 ofType 设置数据类型,association 是通过 javaType 设置数据类型

多对多

1、建表

create table `t_account`(
     `id` int(11) not null primary key auto_increment,
     `name` varchar(11) default null
);

create table `t_course`(
     `id` int(11) not null primary key auto_increment,
     `name` varchar(11) default null
);

create table `account_course`(
     `id` int(11) not null primary key auto_increment,
     `aid` int(11) default null,
     `cid` int(11) default null,
     key `aid`(`aid`),
     key `cid`(`cid`),
     constraint `account_course_ibfk_1` foreign key (`aid`) references
    `t_account`(`id`),
     constraint `account_course_ibfk_2` foreign key (`cid`) references
    `t_course`(`id`)
);

2、创建实体类

@Data
public class Account {
     private Integer id;
     private String name;
     private List<Course> courses; 
}


@Data
public class Course {
     private Integer id;
     private String name;
     private List<Account> accounts; 
}

3AccountRepository

public interface AccountRepository {
     public Account findById(Integer id);
}

4AccountRepository.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.hqq.repository.AccountRepository">

    <resultMap id="accountMap" type="com.hqq.entity.Account">
        <id property="id" column="aid"></id>
        <result property="name" column="aname"></result>
        <collection property="courses" ofType="com.hqq.entity.Course">
            <id property="id" column="cid"></id>
            <result property="name" column="cname"></result>
        </collection>
    </resultMap>

    <select id="findById"  parameterType="java.lang.Integer" resultMap="accountMap">
        select a.id aid,a.name aname,c.id cid,c.name cname
        from t_account a,account_course ac,t_course c
        where a.id = #{id} and a.id = ac.aid and c.id =ac.cid
    </select>
</mapper>

5、CourseRepository

public interface CourseRepository {
    public Course findById(Integer id);
}

6、CourseRepository.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.hqq.repository.CourseRepository">

    <resultMap id="courseMap" type="com.hqq.entity.Course">
        <id column="cid" property="id"></id>
        <result column="cname"  property="name"></result>
        <collection property="accounts" ofType="com.hqq.entity.Account">
            <id column="aid"    property="id"></id>
            <result column="aname"  property="name"></result>
        </collection>
    </resultMap>

    <select id="findById" parameterType="java.lang.Integer" resultMap="courseMap">
        select a.id aid,a.name aname,c.id cid,c.name cname
        from t_account a,account_course ac,t_course c
        where c.id = #{id} and a.id = ac.aid and c.id = ac.cid
    </select>
</mapper>

五、MyBatis逆向工程

逆向⼯程概念

逆向⼯程是 MyBatis 提供的⼀种⾃动化配置⽅案,针对数据表⾃动⽣成 MyBatis 所需要的各种资源 (实体类、Mapper 接⼝、Mapper.xml),但是逆向⼯程只针对于单表,如果数据表之间有级联关系,逆向⼯程⽆法⾃动⽣成级联关系

MyBatis 框架可以⾃动根据数据表, 帮助开发者⽣成实体类、Mapper 接⼝、Mapper.xml ,不用像上面开发每个表每个需求都要写配置写SQL,这就是逆向⼯程

使⽤逆向⼯程

MyBatis 逆向⼯程的组件是 MyBatis Generator,简称 MBG,是专为 MyBatis 框架定制的代码⾃动⽣成解决⽅案,MBG 可以根据数据表结构快速⽣成对应的实体类、Mapper接⼝、Mapper.xml,并且⽀持基本的 CRUD 操作,但是业务逻辑相对复杂的操作就需要开发者⼿动完成

1、创建 Maven ⼯程,pom.xml 添加相关依赖

    <dependencies>
        <!--MyBatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>

        <!--逆向-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.1</version>
        </dependency>
    </dependencies>
2、创建⽬标表 t_account
create table `account`(
     `id` int(11) not null primary key auto_increment,
     `name` varchar(11),
     `password` varchar(11),
     `age` int(11) 
)
3、创建 MBG 配置⽂件 generatorConfifig.xml
  • jdbcConnection 配置数据库连接信息
  • javaModelGenerator 配置 JavaBean 的⽣成策略
  • sqlMapGenerator 配置 SQL 映射⽂件⽣成策略
  • javaClientGenerator 配置 Mapper 接⼝的⽣成策略
  • table 配置要逆向解析的数据表(tableName:表名,domainObjectName;实体类名)
<?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>
    <!--id自定义  targetRuntime 与MyBatis版本号有关-->
    <context id="generator" targetRuntime="MyBatis3">

        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8"
                        userId="root"
                        password="root"></jdbcConnection>

        <javaModelGenerator targetPackage="com.hqq.entity" targetProject="./src/main/java"></javaModelGenerator>

        <sqlMapGenerator targetPackage="com.hqq.repository" targetProject="./src/main/java"></sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER" targetPackage="com.hqq.repository" targetProject="./src/main/java"></javaClientGenerator>

        <!--    domainObjectName表示生成的实体类 叫Account-->
        <table tableName="account" domainObjectName="Account"></table>
    </context>
</generatorConfiguration>

4、创建 GeneratorMain 类,执⾏⾃动⽣成资源的代码

package com.hqq.test;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author 苦恼的java小宝
 * @Date 2022/6/18 22:27
 * @ClassName: Test_0
 * @Version 1.0
 */
public class GeneratorMain {
    public static void main(String[] args) {
        //执行过程中的警告信息
        List<String> warings = new ArrayList<String>();
        //生成的代码重复时,覆盖原代码
        boolean overwrite = true;

        //读取配置文件
        String genCig = "/generatorConfig.xml";
        File configFile =
                new File(GeneratorMain.class.getResource(genCig).getFile());
        ConfigurationParser configurationParser = new ConfigurationParser(warings);
        Configuration configuration = null;
        try {
            configuration = configurationParser.parseConfiguration(configFile);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XMLParserException e) {
            e.printStackTrace();
        }
        //覆盖原代码
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = null;

        try {
            //创建代码生成器
            myBatisGenerator = new MyBatisGenerator(configuration, callback, warings);
        } catch (InvalidConfigurationException e) {
            e.printStackTrace();
        }

        try {
            //执行生成代码
            myBatisGenerator.generate(null);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

六、MyBatis 延迟加载

在进行数据查询时,为了提高数据库查询性能,尽量使用单表查询,因为单表查询比多表关联查询速度要快

如果查询单表就可以满足需求,一开始先查询单表,当需要关联信息时,再关联查询,当需要关联信息再查询这个叫延迟加载,又称为懒加载

1、创建实体类

@Data
public class Customer {
 private Integer id;
 private String name;
 private List<Order> orders;
 }

@Data
public class Order {
 private Integer id;
 private String name;
 private Customer customer; 
}

2confifig.xml 中开启打印 SQL

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

3、创建 OrderRepository

public interface OrderRepository {
     public Order findById(Integer id);
}

<?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.hqq.repository.OrderRepository">
    <resultMap id="orderMap" type="com.hqq.entity.Order">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>
        <association
                property="customer"
                javaType="com.hqq.entity.Customer"
                <!-- cid 的值作为findById的参数 返回对象-->
                select="com.hqq.repository.CustomerRepository.findById"
                column="cid"
        ></association>
    </resultMap>
    
    <select id="findById" parameterType="java.lang.Integer" 
resultMap="orderMap">
         select * from orders where id = #{id}
 </select>
</mapper>

4、创建 CustomerRepository

public interface CustomerRepository {
     public Customer findById(Integer id);
}


<?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.hqq.repository.CustomerRepository">
    <select id="findById" parameterType="java.lang.Integer"
            resultType="com.hqq.entity.Customer">
            select * from customer where id = #{id}
 </select>
</mapper>
5config.xml 中开启延迟加载
<!-- 延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>

6、测试

public class Test {
    public static void main(String[] args) {
        //加载MyBatis配置文件
        InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("config.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory = builder.build(inputStream);

        //获取SqlSession
        SqlSession sqlSession = sessionFactory.openSession();

        //获取实现了自定义接口的代理对象
        OrderRepository orderRespository = sqlSession.getMapper(OrderRepository.class);

        Order order = orderRespository.findById(3);
        System.out.println(order.getCustomer().getName());
        sqlSession.close();
    }
}

MyBatis 延迟加载机制,是实际开发中使⽤频率较⾼的⼀个功能,正确地使⽤延迟加载,可以有效减少Java Application 和数据库的交互次数,从⽽提⾼整个系统的运⾏效率,延迟加载是为了提⾼程序运⾏效率的⼀种⼿段,⼀般应⽤于多表关联查询的业务场景


七、MyBatis 缓存

使⽤缓存的作⽤也是为了减少 Java Application 与数据库的交互次数,从⽽提升程序的运⾏效率

⼀级缓存

MyBatis ⾃带⼀级缓存,并且是⽆法关闭的,⼀直存在,⼀级缓存的数据存储在 SqlSession

即使⽤同⼀个 SqlSession 进⾏查询操作的时候,⼀级缓存存在,如果使⽤多个 SqlSession 进⾏查询操作,⼀级缓存不存在,缓存只针对于查询

如果 SqlSession 执⾏了增、删、改操作,MyBatis 会动清空 SqlSession 缓存中的数据,以此来保证数据的⼀致性

1、实体类 

@Data
public class MyClass {
 private Integer id;
 private String name; 
}

2、Mapper.java

public interface MyClassRepository {
 public MyClass findById(Integer id);
}

3Mapper.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.hqq.repository.MyClassRepository">
     <select id="findById" parameterType="java.lang.Integer"
        resultType="com.hqq.entity.MyClass">
         select * from t_classes where id = #{id}
     </select>
</mapper>
4Test
public class Test_0 {
    public static void main(String[] args) {
        InputStream inputStream =
                Test_0.class.getClassLoader().getResourceAsStream("config.xml");
        //FactoryBuilder -> Factory -> Session -> Repository
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        MyClassRepository myClassRepository = sqlSession.getMapper(MyClassRepository.class);
        
        MyClass myClass = myClassRepository.findById(1);
        System.out.println(myClass);
        MyClass myClass1 = myClassRepository.findById(1);
        System.out.println(myClass1);

    }
}

结果:sql语句只会执行一次,第二次不用查询语句直接返回

⼆级缓存

MyBatis ⼆级缓存是⽐⼀级缓存作⽤域更⼤的缓存机制,它是 Mapper 级别的,只要是同⼀个 Mapper,⽆论使⽤多少个 SqlSession,数据都是共享的

MyBatis ⼆级缓存默认是关闭的,需要使⽤时可以通过配置⼿动开启

MyBatis 可以使⽤⾃带的⼆级缓存,也可以使⽤第三⽅ ehcache ⼆级缓存

⾃带⼆级缓存

1confifig.xml 中配置开启⼆级缓存

<settings>
     <!-- 开启⼆级缓存 -->
     <setting name="cacheEnabled" value="true"/>
</settings>

2Mapper.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.hqq.repository.MyClassRepository">
     <!--配置二级缓存-->
     <cache></cache>
     <select id="findById" parameterType="java.lang.Integer"
        resultType="com.hqq.entity.MyClass">
         select * from t_classes where id = #{id}
 </select>
</mapper>

3、实体类实现 Serializable 接⼝

@Data
public class MyClass implements Serializable {
     private Integer id;
     private String name; 
}

4、测试

public class Test6 {
 public static void main(String[] args) {
     InputStream inputStream =
        Test2.class.getClassLoader().getResourceAsStream("config.xml");
     SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
     SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
     SqlSession sqlSession = sqlSessionFactory.openSession();

     MyClassRepository myClassRepository = sqlSession.getMapper(MyClassRepository.class);
     MyClass myClass = myClassRepository.findById(1);
     System.out.println(myClass);
     sqlSession.close();

     sqlSession = sqlSessionFactory.openSession();
     myClassRepository = sqlSession.getMapper(MyClassRepository.class);
     MyClass myClass2 = myClassRepository.findById(1);
     System.out.println(myClass2);
 }
}

只会执行一次SQL语句

第三⽅ ehcache ⼆级缓存

1pom.xml

<!-- ehcache -->
<dependency>
     <groupId>net.sf.ehcache</groupId>
     <artifactId>ehcache-core</artifactId>
     <version>2.4.3</version>
</dependency> 

<dependency>
 <groupId>org.mybatis</groupId>
 <artifactId>mybatis-ehcache</artifactId>
 <version>1.0.0</version>
</dependency>

2resources 路径下创建 ehcache.xml

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

3、confifig.xml 中配置⼆级缓存

<settings>
     <!-- 开启⼆级缓存 -->
     <setting name="cacheEnabled" value="true"/>
</settings>

4Mapper.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.hqq.repository.MyClassRepository">
    <!-- 开启⼆级缓存 -->
     <cache type="org.mybatis.caches.ehcache.EhcacheCache" >
     <!-- 缓存创建以后,最后⼀次访问缓存的时间⾄失效的时间间隔 -->
     <property name="timeToIdleSeconds" value="3600"/>
     <!-- 缓存⾃创建时间起⾄失效的时间间隔-->
     <property name="timeToLiveSeconds" value="3600"/>
     <!-- 缓存回收策略,LRU移除近期最少使⽤的对象 -->
     <property name="memoryStoreEvictionPolicy" value="LRU"/>
     </cache>

     <select id="findById" parameterType="java.lang.Integer"
        resultType="com.hqq.entity.MyClass">
         select * from t_classes where id = #{id}
     </select>
</mapper>

5、实体类不需要实现序列化接⼝

@Data
public class MyClass {
     private Integer id;
     private String name; 
}

6、测试如上

只会执行一次SQL语句


八、MyBatis 动态 SQL

静态实现

User类

@Data
public class User {
    private Integer id;
    private String userName;
    private String password;
    private Integer age;
}

需求

  • 通过 id username 查询 User
  • 通过 username password 查询 User
  • 通过 password age 查询 User

UserRepository 接口

public interface UserRepository {
    public User findByUser1(User user);
    public User findByUser2(User user);
    public User findByUser3(User user);
}

UserRepository.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.hqq.repository.UserRepository">
    <select id="findByUser1" parameterType="User" resultType="User">
        select * from t_user where id = #{id} and username = #{username}
    </select> 
    
    <select id="findByUser2" parameterType="User" resultType="User">
        select * from t_user where username = #{username} and password = #{password}
    </select> 
    
    <select id="findByUser3" parameterType="User" resultType="User">
        select * from t_user where password = #{password} and age = #{age}
    </select>
</mapper>

动态实现

select * from t_user 
where 
id = #{id} 
and username = #{username} 
and password = #{password}
and age = #{age}

UserRepository

public interface UserRepository {
    public User findByUser(User user);
}

UserRepository.xml        (if标签)

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqq.repository.UserRepository">
 <select id="findByUser" parameterType="com.hqq.entity.User"
resultType="com.hqq.entity.User">
     select * from t_user
     <where>
         <if test="id!=null">
            id = #{id}
         </if>
         <if test="username!=null">
             and username = #{username}
         </if>
         <if test="password!=null">
             and password = #{password}
         </if>
         <if test="age!=null">
             and age = #{age}
         </if>
     </where>
 </select>
</mapper>


  • choosewhen标签
<select id="findByUser" parameterType="com.hqq.entity.User"
resultType="com.hqq.entity.User">
     select * from t_user
     <where>
         <choose>
             <when test="id!=null">
                 id = #{id}
             </when>
             <when test="username!=null">
                 and username = #{username}
             </when>
             <when test="password!=null">
                 and password = #{password}
             </when>
             <when test="age!=null">
                 and age = #{age}
             </when>
         </choose>
     </where>
</select>
  • trim标签

通过设置 prefifix suffix 参数来完成使⽤的

<select id="findByUser" parameterType="com.hqq.entity.User"
resultType="com.hqq.entity.User">
     select * from t_user
     <trim prefix="where" prefixOverrides="and">

         <if test="id!=null">
             id = #{id}
         </if>

         <if test="username!=null">
             and username = #{username}
         </if>

         <if test="password!=null">
             and password = #{password}
         </if>

         <if test="age!=null">
             and age = #{age}
         </if>

     </trim>
</select>
  • set

set 标签⽤于 Update 操作,会⾃动根据参数选择⽣成 SQL 语句

UserRepository

public interface UserRepository {
     public int update(User users);
}

UserRepository.xml

<update id="update" parameterType="com.hqq.entity.User">
     update t_user
     <set>
         <if test="username!=null">
             username = #{username},
         </if>

         <if test="password!=null">
             password = #{password},
         </if>

         <if test="age!=null">
             age = #{age}
         </if>
     </set>
             where id = #{id}
</update>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值