Mybatis万字教程 (一次订阅能看所有专栏)

一、简介

1、什么是MyBatis

  • MyBatis是一款优秀的持久化框架
  • 它支持定制化SQL,存储过程以及高级映射
  • MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
  • MyBatis可以使用简单的XML或者注解来配置和映射原生类型,接口和Java的POJO
  • MyBatis本事apache的一个开源项目iBatis,2010年这个项目由apache迁移到google code并改名为iBatis。2013年迁移到github

maven依赖

<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
</dependency>

2、持久化

2.1 数据持久化

  • 持久化就是讲程序的数据在持久的状态和瞬时状态进行转化的过程
  • 内存:断电即失
  • 数据库、IO文件持久化(两种持久化数据的方式)

为什么需要持久化

1、有一些数据比较重要,不能让他丢失

2、内存太贵,存放数据有限

2.2 持久层

持久层是完成持久化工作的代码块,持久化是一个动作,而持久层是一个概念

3、为什么使用MyBatis

1、帮助程序员将数据存储到数据库中

2、传统的JDBC代码太过于复杂,MyBatis简化了操作

3、SQL语句和代码分离,提高了可维护性,支持动态编写sql

4、提供对象关系映射标签,支持对象与数据库中ORM字段关系的维护

二、简单Mybatis程序案例

1、搭建环境

1、创建表,执行下列SQL语句

create table user(
 id int(20) not null primary key,
    name varchar(30) default null,
    pwd varchar(30) default null,
)engine=innoDB default charset=utf8

insert into user(id,name,pwd) values
(1,'kuangshen','123456'),
(2,'zhangsan','123456'),
(3,'lisi','123456')

2、新建项目

新建一个普通的maven项目,导入以下依赖

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

    <!-- mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>

    <!--junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2、创建一个模块

  • 编写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">

<!-- 核心配置文件-->
<configuration>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisk"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>
</configuration>
  • 编写MyBaits工具类
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

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

public class MyBatisUtils {
    
    

    private static SqlSessionFactory sqlSessionFactory;

    static {
    
    
        try {
    
    
        //使用Mybatis第一步,获取sqlSessionFactory对象
          String resource = "SqlMapperConfig.xml";
          InputStream inputStream = Resources.getResourceAsStream(resource);
           sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }

    }

    //既然有了 SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了。SqlSession 完全包含了面向数据库执行 SQL
    // 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句

    public static SqlSession getSqlSession(){
    
    
        return sqlSessionFactory.openSession(true);

    }
}

3、编写代码

  • 实体类User
//实体类
public class User {
    
    
    private int id;
    private String name;
    private String pwd;

    public User(int id, String name, String pwd) {
    
    
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public User() {
    
    
    }

    public int getId() {
    
    
        return id;
    }

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

    public String getName() {
    
    
        return name;
    }

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

    public String getPwd() {
    
    
        return pwd;
    }

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

    @Override
    public String toString() {
    
    
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

  • 接口UserDao
public interface UserDao {
    
    
    List<User> getUserList();
}

  • 实现类UserDaoImpl更改为UserDao.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 namespace="com.kuang.dao.UserrDao">
    <!-- 查询标签,查询运距-->
    <select id="getUserrList" resultType="com.kuang.pojo.Userr">
    select * from user
  </select>
</mapper>

4、测试

    @Test
    public void test(){
    
    
        //1.获得sqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //2.执行sql,方式一
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> userList = mapper.getUserList();

       /*方式二
         List<User> userList = (User)
 session.selectList("com.kuang.dao.UserDao.getList", 101);
        */
        for (User user:userList) {
    
    
            System.out.println(user);
        }

        //关闭SqlSession
        sqlSession.close();
    }

三、增删查改

1、namespace

namespace 绑定一个对应的Dao/Mapper 接口

2、select —查询操作

  • id:对应接口中的方法名,注意MyBatis不支持方法的重载,一旦出现同名的方法,这个id就无法定位
  • resultType:SQL语句执行的返回类型
  • parameterType:参数类型

编写接口中的方法

    /**
     * 查询全部用户
     * @return
     */
    List<User> getUserList();

    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    User getUserById(int id);

对应的xml文件

<!-- 查询标签,查询运距-->
    <select id="getUserList" resultType="com.kuang.pojo.User">
    select * from user
    </select>

    <select id="getUserById" resultType="com.kuang.pojo.User" parameterType="int">
        select * from user where id = #{id}
    </select>

测试

@Test
    public void test(){
    
    
        //1.获得sqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //2.执行sql
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();

        for (User user:userList) {
    
    
            System.out.println(user);
        }

        //关闭SqlSession
        sqlSession.close();
    }

    @Test
    public void testgetUserById(){
    
    
        SqlSession sqlSession=MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);

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

3、insert—插入操作

编写接口中的方法

 /**
     * 插入用户
     * @param user
     * @return
     */
    int addUser(User user);

编写对应的mapper.xml文件中的sql语句

<insert id="addUser" parameterType="com.kuang.pojo.User" >
        insert into user ( name, pwd ) values (#{name},#{pwd})
    </insert>
 /**
 * 增删改需要提交事务
 /
   @Test
    public  void addUser(){
        SqlSession sqlSession=MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setName("笨蛋");
        user.setPwd("5454");

        int i = mapper.addUser(user);
        if(i>0){
            System.out.println("插入成功");
        }

        //提交事务
        sqlSession.commit();


        sqlSession.close();
    }

4、update—修改操作

编写接口

/**
     * 修改用户
     * @param user
     * @return
     */
    int updateUser(User user);

编写mapper.xml中的sql语句

<update id="updateUser" parameterType="com.kuang.pojo.User">
        update user set name=#{name}, pwd=#{pwd} where id= #{id}
    </update>

测试

 @Test
    public  void updateUser(){
    
    
        SqlSession sqlSession=MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setId(5);
        user.setName("二哈");
        user.setPwd("54514");

        int i = mapper.updateUser(user);
        if(i>0){
    
    
            System.out.println("修改成功");
        }

        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }

5、delete—删除操作

编写接口

/**
     * 根据id删除用户
     * @param id
     * @return
     */
    int deleteUser(int id);

编写mapper.xml中sql语句

 <delete id="deleteUser">
        delete from user where id= #{id}
    </delete>

测试

 @Test
    public void deleteUser(){
    
    
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteUser(5);

        if(i>0){
    
    
            System.out.println("删除成功");

        }
        sqlSession.commit();
        sqlSession.close();
    }

6、万能的Map

假设,我们的实体类或者数据库中的表字段或者参数过多,我们应当考虑使用Map

编写接口

int addUserByMap(Map<String,Object> map)

对应的mapper.xml的sql语句

<!-- 对象中的属性,可以直接取出来-->
<insert id ="addUserByMap" parameterType="map">
    insert into user(id,pwd) values (#{userid},#{password})
</insert>

测试类

@Test
public void test_addUsetByMap(){
    
    
    SqlSession sqlsession=MybatisUtils.getSqlSession();
    UserMapper mapper= sqlSession.getMappper(UserMapper.class);
    
    Map<String,Object> map=new HashMap<String,Object>();
    map.put("userid",5);
    map.put("password","2333");
    mapper.addUserByMap(map);
    sqlSession.commit();
    sqlSession.close();
}

  • 使用Map传递参数,直接在sql中取出key即可
  • 对象传参,直接在sql中取出对象的属性即可
  • 只要一个基本数据类型的参数时,可以直接在sql中取到,不用写parameterType

7、模糊查询

1、在java代码执行的时候,传通配符%

List<User> userList=mapper.getUserLike("%zhang%")

2、在sql拼接的时候使用通配符

<selsect id="getUserLike" resultType="com.kuang.pojo.User">
   select * from user where name like "%"#{name}"%"
</selsect>

四、配置文件解析

1、核心配置文件

sqlMapperConfig.xml文件

MyBatis的配置文件包含了会影响MyBatis行为的设置和属性信息。配置文档的顶层结构如下

  1. configuration(配置)

  2. properties(属性)

  3. settings(设置)

  4. typeAliases(类型别名)

  5. typeHandlers(类型处理器)

  6. objectFactory(对象工厂)

  7. plugins(插件)

  8. environments(环境配置)

  9. environment(环境变量)

  10. transactionManager(事务管理器)

  11. dataSource(数据源)

  12. databaseIdProvider(数据库厂商标识)

  13. mappers(映射器)

2、环境配置(enviroments)

MyBatis可以配置成适应多种环境

尽管可以配置多个环境,但是每个sqlSessionFactory实例只能选择一种

MyBatis默认的事务管理器就是JDBC,连接池:POOLED

3、属性(Properties)

可以通过properties属性来实现引用的配置文件

这些属性都是外部配置,可以动态替换

编写db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
username=root
password=123456

在核心配置文件里引入

<!--引入外部配置文件 -->
    <properties resource="db.properties">
        <property name="username" value=""/>
        <property name="password" value=""/>
    </properties>

4、类型别名(typeAliases)

<!--可以给实体类取别名 -->
    <typeAliases>
        <typeAlias type="com.kuang.pojo.User" alias="User"/>
    </typeAliases>

也可以配置一个包扫描,这样就不用一个个的为实体类配置别名了。配置扫描实体类的包后,它的默认别名就是这个类的类名,首字母小写

<!--可以给实体类取别名 -->
    <typeAliases>
        <package name=”com.kuang.pojo”/>
    </typeAliases>


  • 当实体类比较少的时候,使用第一种方式
  • 当实体类比较多的时候,使用第二种方式
  • 第一种可以自定义别名,第二种则是自动生成的,如果非要修改,需要在实体类上加注解
@Alias("haha")
public class Author{
    
    
    
}

5、setting

6、其他配置

7、映射器(mapper)

MapperRegister:注册绑定我们的mapper文件

有四种方式

  • 使用相对于类路径的资源应用
<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>


  • 使用完全限定资源定位符
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>


  • 使用映射器接口实现类的完全限定类名
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

  • 使用包扫描的方式
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>


8、MyBatis生命周期和作用域

在这里插入图片描述

sqlSessionFactoryBuilder:局部变量,一旦创建SqlSessionFactory之后,就不需要这个了‘

sqlSessionFactory:相当于数据库的连接池,一旦被创建,在应用运行期间就会一直存在,没有任何理由丢弃或创建另一个实例。它的最佳作用域是应用作用域

sqlSession:连接到连接池的一个请求,并不是线程安全的,因此不能被共享,它的最佳作用域是请求作用域或者方法作用域,用完之后要赶紧关闭

在这里插入图片描述

五、属性名和字段名不一致的解决方式

1、起别名

<select id="getUserById" resultType="com.kuang.pojo.User">
  select id,name,pwd as password from user where id =#{id}
</select>

2、resultMap

结果集映射

<resultMap id= "UserMap" type="User">
   <!-- column数据库的字段,property实体类中的属性 -->
    <result column="id" property="id" />
    <result column="name" property="name" />
    <result column="pwd" property="password" />
</resultMap>

<select id="getUserById" resultMap="userMap">
   select * from user where id=#{id}
</select>

六、日志

1、日志工厂

如果一个数据库操作出现了异常,我们需要排错,那么日志将会是最好的助手

过去:输出到控制台,debug调试

现在:日志工厂

MyBatis支持以下日志工厂

  • SLF4J
  • LOG4J
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING
  • NO_LOGGING

在MyBatis中具体使用哪一个日志实现,可以在设置中设定

STDOUT_LOGGING

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

在这里插入图片描述

2、Log4J

2.1 什么是Log4j?

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

2.2 使用Log4j

1、导入log4j的包

<!--log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>


2、log4j.properties

#将等级为DEBUG的日志信息输出到console和file两个目的地
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshold=DEBUG

log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

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

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

3、配置log4j为日志实现

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

简单使用

1、在要使用的log4j的类中,导入的包import org.apache.log4j.Logger

2、日志对象,参数为当前类的class

static Logger logger=Logger.getLogger(UserDaoTest.class)

3、日志级别

logger.info()

logger.debug()

logger.error()

七、分页

分页是为了减少数据的处理量

1、使用Limit分页

语法:select * from user limit startIndex, pageSize

select * from user limit 3

使用MyBatis实现分页,核心就是SQL语句

1、接口

/**
     * 分页
     * @param map
     * @return
     */
    List<User> getUserByLimit(Map<String,Integer> map);

2、Mapper.xml

<select id="getUserByLimit" resultType="user" parameterType="map">
         select * from user limit #{startIndex},#{pageSize}
    </select>

3、测试

@Test
    public void getUserByLimit(){
    
    
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        HashMap<String,Integer> map=new HashMap<String, Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit) {
    
    
            System.out.println(user);
        }
        sqlSession.close();
    }

2、使用RowBounds

不使用SQL实现分页

1、接口

List<User> getUserByRowBounds();

2、mapper.xml

<select id="getUserByRowBounds" resultMap="UserMap">
    select * from user
</select>

3、测试

@Test
public  void getUserByRowBounds(){
    
    
    SqlSession sqlSession=MybatisUtils.getSqlSession();
    //RowsBounds实现
    RowBounds rowBounds = new RowBounds(1,2);
    //通过java代码来实现分页
    List<User> userList=sqlSession.selectList("com.kuang.dao.UserMapper.getUserByRowBounds",null,rowBounds);
    
    for(User user:userList){
    
    
        System.out.println(user);
    }
    
    sqlSession.close();
}

3、使用分页插件

PageHelper

八、使用注解开发

1、面向接口编程

接口的理解

  • 接口是用来定义规范和约束
  • 接口的本身反应了系统设计人员对系统的抽象理解
  • 接口有两类,一类是对一个个体的抽象,它可以对应为一个抽象体;第二类是对个体的某一方面的抽象,形成一个抽象面

两个面向的区别

  • 面向对象是指,我们再考虑问题的时候,以对象为单位,考虑它的属性和方法
  • 面向过程是指,我们再考虑问题的时候,以一个具体的流程为单位,考虑它的实现
  • 接口设计与非接口设计是针对复用技术而言的,与面向过程和面向对象不一样,它更多的是体现对系统的整体架构

2、使用注解

1、注解在接口上实现

@Select("select * from user")
List<User> getUser();

2、需要在核心配置文件中绑定接口

<!-- 绑定接口-->
<mappers>
    <mapper class="com.kuang.dao.UserMapper"></mapper>
</mappers>

本质:反射机制

底层:代理模式

3、CRUD

我们再工具类创建的时候自动提交事务

public static SqlSession getSqlSession(){
    
    
   return sqlSessionFactory.openSession(true);
}

编写接口

public interface UserMapper{
    
    
    @Select("select * from user")
    List<User> getUsers();
    
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id)
}

关于@Param()注解

  • 当方法中存在多个参数(基本数据类型或String类型)的时候,所有的参数需要加上@Param注解
  • 引用类型不需要加

九、Lombok插件

使用步骤:

1、在IDEA中安装Lombok插件

2、在项目中导入lombok的jar包

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
</dependency>

3、在实体类上加注解


十、查询

十一、动态SQL

根据不同的条件生成不同的SQL语句

1、if

  //查询博客
    List<Blog> queryBlogIF(Map map);
<select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from blog where 1=1
        <if test="title!=null">
            and title=#{title}
        </if>
        <if test="author!=null">
            and author=#{author}
        </if>
    </select>

测试

@Test
    public void queryBlogIF(){
    
    
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map=new HashMap();
        map.put("title","微服务如此简单");
        List<Blog> blogs = mapper.queryBlogIF(map);

        for (Blog blog : blogs) {
    
    
            System.out.println(blog);
        }

        //工具类中配置了事务的自动提交
        sqlSession.close();
    }

2、choose(when,otherwise)

 <select id="queryBlogChoose" resultType="Blog" parameterType="map">
        select * from blog
        <where>
            <choose>
                <when test="title!=null">
                    title=#{title}
                </when>
                <when test="author!=null">
                    and author=#{author}
                </when>
                <otherwise>
                    and views=#{views}
                </otherwise>
            </choose>
        </where>
    </select>

3、trim(where,set)

<update id="updateBlog" parameterType="map" >
        update blog
        <set>
            <if test="title!=null">
                title=#{title},
            </if>
            <if test="author!=null">
                author=#{author}
            </if>
        </set>
        where id=#{id}
    </update>

4、foreach

通常在构建in条件语句的时候,用foreach比较多

<select id="queryBlogForEach" parameterType="map" resultType+"blog">
   select * from blog
    <where>
          <foreach collection="ids" item="id" open="and (" close=")" separator ="or">
              id =#{id}
        
        </foreach>
    </where>
</select>

5、sql片段

我们可以将一些公共部分抽取出来,方便复用

1、使用SQL标签抽取公共部分

<sql id="if-title-author">
   <if test="title!=null">
       title=#{title}
    </if>
    <if test="author !=null">
        and author=#{author}
    </if>
</sql>

2、在需要使用的地方使用Include标签引用即可

<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from blog
    <where>
       <include refid="if-title-author"></include>
    </where>

</select>

十二、缓存

1、简介

1、什么是缓存?

存在内存中的临时数据

将用户经常查询的数据放在缓存中,用户去查询数据的时候就不用从磁盘上查询,从缓存上查询提高了查询效率,解决了高并发系统的性能问题

2、为什么使用缓存?

减少和数据库交互的次数,减少系统开销,提高系统效率

3、什么样的数据能使用缓存?

经常查询并且不经常改变的数据

2、MyBatis缓存

MyBatis包含了一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存,缓存可以极大的提高查询效率

MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存

  • 默认情况下系统中只有一级缓存开启(SqlSession级别的缓存)
  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存
  • 为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来定义二级缓存

3、一级缓存

一级缓存也叫本地缓存:

  • 与数据库同一次回话期间查询到的数据会放在本地缓存中
  • 之后如果需要相同的数据直接从缓存中拿,不需要查询数据库

1、开启日志

2、测试在要给Session中查询两次相同的记录

3、查看日志输出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrmsYjtk-1614248426300)(Mybatis%E7%AC%94%E8%AE%B0.assets/image-20201011100858347.png)]

缓存失效的情况

1、查询不同的数据

2、增删改操作,可能会改变原来的数据,所以必然会刷新缓存

3、查询不同的Mapper.xml

4、手动刷新缓存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MzsZ4LMa-1614248426304)(Mybatis%E7%AC%94%E8%AE%B0.assets/image-20201011101032878.png)]

一级缓存默认开启,只在一次sqlSession中有效,也就是在拿到连接和关闭连接这个区间段

4、二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
  • 工作机制

1、一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中

2、如果当前会话关闭了,这个会话对应的一级缓存就没有了,但我们想要的是,会话关闭,一级缓存中的数据会被保存到二级缓存中去

3、新的会话查询信息,可以直接从二级缓存中获取内容

4、不同的mapper查询出的数据都会放在自己对应的map中

步骤

1、开启全局缓存

2、在要使用二级缓存的Mapper中开启

猜你喜欢

转载自blog.csdn.net/weixin_54707168/article/details/114098012