Mybatis缓存的机制解析与二级缓存的详细分析-----Mybatis框架

发布于:2023-09-22 ⋅ 阅读:(61) ⋅ 点赞:(0)
内存是临时存储数据的空间,断电后消失
硬盘:持久化的文件存储在硬盘当中,关机后文件仍旧保留
实际上,各大关系型数据库的数据都是存储在文件当中的
各大关系型数据库的数据都是存储在文件中的,mysql的信息通过orm映射成java对象
Mybatis的缓存机制,将SQL如select * from t_car where id = 1;
执行DQL语句的时候将查询结果放到缓存中,如果下次还是执行完全相同的DQL,就直接从缓存拿数据
目的在于提高查询效率和执行效率,减少查询数据库的次数
通过了减少IO的方式提速,IO:读文件和写文件
如果缓存读取的文件被修改了,那么mybatis就会自动清除缓存中保留的数据
缓存通常是我们程序开发中优化程序的重要手段,我们常用的缓存技术如下
字符串常量池(直接保存在字符串常量池,不需要重新创建)整数型常量池
线程池(创建多个线程放在里面)数据库连接池
在实际的生产环境下,多方面优化,缓存就是优化的一个方面,数据库表的索引的优化等等
缓存:提前把数据放到缓存中(内存),下一次用的时候,可以直接从缓存中取出来,提升了访问效率cache
mybatis提供了两级缓存
一级缓存,将数据存储到SqlSession中,二级缓存,将数据存储到SqlSessionFactory中
还可以集成其他第三方的缓存,比如EthCache(java开发的),MemCache(C语言开发的)
查询语句的信息存到SqlSession中(当前的一次会话),可以理解为一级缓存,如果存到SqlSessionFactory中,代表着一个环境(数据库environment)
如果执行的多个SQL都是一样的就直接从这个SqlSession中取信息,这就是一级缓存
缓存只针对DQL语句,DML语句必须连接数据库
默认情况下,Mybatis的二级缓存是开启的,只需要在对应的SqlMapper下添加标签即可
<!--    添加一个cache标签即可-->
除此以外,被查询出的结果对象还必须实现Serializable(序列化接口)
让它得以序列化才能实现
SqlSession对象被关闭或提交后,一级缓存的数据才会被写入到二级缓存,此时二级缓存才可用
当我们启用了二级缓存以后,二级缓存会引出一个缓存命中率的信息
内存是临时存储数据的空间,断电后消失
硬盘:持久化的文件存储在硬盘当中,关机后文件仍旧保留
实际上,各大关系型数据库的数据都是存储在文件当中的
各大关系型数据库的数据都是存储在文件中的,mysql的信息通过orm映射成java对象
Mybatis的缓存机制,将SQL如select * from t_car where id = 1;
执行DQL语句的时候将查询结果放到缓存中,如果下次还是执行完全相同的DQL,就直接从缓存拿数据
目的在于提高查询效率和执行效率,减少查询数据库的次数
通过了减少IO的方式提速,IO:读文件和写文件
如果缓存读取的文件被修改了,那么mybatis就会自动清除缓存中保留的数据
缓存通常是我们程序开发中优化程序的重要手段,我们常用的缓存技术如下
字符串常量池(直接保存在字符串常量池,不需要重新创建)整数型常量池
线程池(创建多个线程放在里面)数据库连接池
在实际的生产环境下,多方面优化,缓存就是优化的一个方面,数据库表的索引的优化等等
缓存:提前把数据放到缓存中(内存),下一次用的时候,可以直接从缓存中取出来,提升了访问效率cache
mybatis提供了两级缓存
一级缓存,将数据存储到SqlSession中,二级缓存,将数据存储到SqlSessionFactory中
还可以集成其他第三方的缓存,比如EthCache(java开发的),MemCache(C语言开发的)
查询语句的信息存到SqlSession中(当前的一次会话),可以理解为一级缓存,如果存到SqlSessionFactory中,代表着一个环境(数据库environment)
如果执行的多个SQL都是一样的就直接从这个SqlSession中取信息,这就是一级缓存
缓存只针对DQL语句,DML语句必须连接数据库
默认情况下,Mybatis的二级缓存是开启的,只需要在对应的SqlMapper下添加标签即可
<!--    添加一个cache标签即可-->
除此以外,被查询出的结果对象还必须实现Serializable(序列化接口)
让它得以序列化才能实现
SqlSession对象被关闭或提交后,一级缓存的数据才会被写入到二级缓存,此时二级缓存才可用
当我们启用了二级缓存以后,二级缓存会引出一个缓存命中率的信息
package com.powernode.mybatis.Test;

import com.powernode.mybatis.mappers.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtils;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CarMapperTest
{
    private static final Logger logger = LoggerFactory.getLogger(CarMapperTest.class);
    @Test
    public void TestselectById() throws Exception
    {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(3L);
        logger.info(car.toString());
        //两个Mapper也只执行一次DQL语句,充分说明了DQL语句只会执行一次在一个SqlSession会话中
        //和反射生成出的调用方法的对象无关
        //增加一个sqlSession就不再是执行一次了,因为目前是在一级缓存SqlSession中调用的
        SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
        CarMapper m = session.getMapper(CarMapper.class);
        //不再执行SQL语句了
        Car c = m.selectById(3L);
        //不走缓存的情况:不是同一个SqlSession会话对象,不是同一条SQL(查询条件不一样)
        //第一次DQL和第二次DQL之间以下两个操作任意出现一个都会清空缓存
        //1>执行了SQLSession的clearCache方法(手动清空缓存)
        //2>或执行了DML类型的语句,不管是那张表,都会清空缓存
        logger.info(c.toString());
        SqlSessionUtils.close(sqlSession);
    }
    @Test
    public void sessionTest()
    {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(3L);
        logger.info(car.toString());
        //手动清除Sql缓存
//        sqlSession.clearCache();
        //因为执行了DML语句,会清空我们的缓存,不管是不是同一张表,他都会清空缓存
        mapper.insertClazz(1002,"高三三班");
        CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(3L);
        logger.info(car1.toString());
    }
    @Test
    public void selectByIdSecondCache() throws Exception
    {
        SqlSessionFactory sqb = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqb.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectByIdSecondCache(3L);
        logger.info(car.toString());
        sqlSession.close();
        SqlSession sqlSession1 = sqb.openSession();
        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        Car car1 = mapper1.selectByIdSecondCache(3L);
        logger.info(car1.toString());
    }
}

package com.powernode.mybatis.Test;

import com.powernode.mybatis.mappers.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtils;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CarMapperTest
{
    private static final Logger logger = LoggerFactory.getLogger(CarMapperTest.class);
    @Test
    public void TestselectById() throws Exception
    {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(3L);
        logger.info(car.toString());
        //两个Mapper也只执行一次DQL语句,充分说明了DQL语句只会执行一次在一个SqlSession会话中
        //和反射生成出的调用方法的对象无关
        //增加一个sqlSession就不再是执行一次了,因为目前是在一级缓存SqlSession中调用的
        SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
        CarMapper m = session.getMapper(CarMapper.class);
        //不再执行SQL语句了
        Car c = m.selectById(3L);
        //不走缓存的情况:不是同一个SqlSession会话对象,不是同一条SQL(查询条件不一样)
        //第一次DQL和第二次DQL之间以下两个操作任意出现一个都会清空缓存
        //1>执行了SQLSession的clearCache方法(手动清空缓存)
        //2>或执行了DML类型的语句,不管是那张表,都会清空缓存
        logger.info(c.toString());
        SqlSessionUtils.close(sqlSession);
    }
    @Test
    public void sessionTest()
    {
        SqlSession sqlSession = SqlSessionUtils.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(3L);
        logger.info(car.toString());
        //手动清除Sql缓存
//        sqlSession.clearCache();
        //因为执行了DML语句,会清空我们的缓存,不管是不是同一张表,他都会清空缓存
        mapper.insertClazz(1002,"高三三班");
        CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(3L);
        logger.info(car1.toString());
    }
    @Test
    public void selectByIdSecondCache() throws Exception
    {
        SqlSessionFactory sqb = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqb.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectByIdSecondCache(3L);
        logger.info(car.toString());
        sqlSession.close();
        SqlSession sqlSession1 = sqb.openSession();
        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        Car car1 = mapper1.selectByIdSecondCache(3L);
        logger.info(car1.toString());
    }
}
package com.powernode.mybatis.pojo;

import java.io.Serializable;

public class Car implements Serializable
{
    //这是一个封装汽车相关信息的普通的java类,数据库表中的字段应该和属性一一对应
    //为什么使用包装类,因为当我们查值的时候,返回值有可能是null
    //避免数据不兼容
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;
    public Car(){};

    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }

    public Long getId() {
        return id;
    }

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

    public String getCarNum() {
        return carNum;
    }

    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getGuidePrice() {
        return guidePrice;
    }

    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }

    public String getProduceTime() {
        return produceTime;
    }

    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }

    public String getCarType() {
        return carType;
    }

    public void setCarType(String carType) {
        this.carType = carType;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guidePrice=" + guidePrice +
                ", produceTime='" + produceTime + '\'' +
                ", carType='" + carType + '\'' +
                '}';
    }
}

package com.powernode.mybatis.pojo;

import java.io.Serializable;

public class Car implements Serializable
{
    //这是一个封装汽车相关信息的普通的java类,数据库表中的字段应该和属性一一对应
    //为什么使用包装类,因为当我们查值的时候,返回值有可能是null
    //避免数据不兼容
    private Long id;
    private String carNum;
    private String brand;
    private Double guidePrice;
    private String produceTime;
    private String carType;
    public Car(){};

    public Car(Long id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {
        this.id = id;
        this.carNum = carNum;
        this.brand = brand;
        this.guidePrice = guidePrice;
        this.produceTime = produceTime;
        this.carType = carType;
    }

    public Long getId() {
        return id;
    }

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

    public String getCarNum() {
        return carNum;
    }

    public void setCarNum(String carNum) {
        this.carNum = carNum;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Double getGuidePrice() {
        return guidePrice;
    }

    public void setGuidePrice(Double guidePrice) {
        this.guidePrice = guidePrice;
    }

    public String getProduceTime() {
        return produceTime;
    }

    public void setProduceTime(String produceTime) {
        this.produceTime = produceTime;
    }

    public String getCarType() {
        return carType;
    }

    public void setCarType(String carType) {
        this.carType = carType;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", carNum='" + carNum + '\'' +
                ", brand='" + brand + '\'' +
                ", guidePrice=" + guidePrice +
                ", produceTime='" + produceTime + '\'' +
                ", carType='" + carType + '\'' +
                '}';
    }
}
<?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>
    <properties resource="jdbc.properties"/>
    <settings>
<!--        全局的延迟加载的开关,默认为false,全局的分步查询都支持-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="SLF4J"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <typeAliases>
        <package name="com.powernode.mybatis.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.powernode.mybatis.mappers"/>
    </mappers>
</configuration>

<?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>
    <properties resource="jdbc.properties"/>
    <settings>
<!--        全局的延迟加载的开关,默认为false,全局的分步查询都支持-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="SLF4J"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <typeAliases>
        <package name="com.powernode.mybatis.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.powernode.mybatis.mappers"/>
    </mappers>
</configuration>
package com.powernode.mybatis.mappers;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;

public interface CarMapper
{
    Car selectByIdSecondCache(Long id);
    //根据ID获取Car信息
    Car selectById(Long id);
    int insertClazz(@Param("cid") Integer cid,@Param("cname") String cname);
}

package com.powernode.mybatis.mappers;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;

public interface CarMapper
{
    Car selectByIdSecondCache(Long id);
    //根据ID获取Car信息
    Car selectById(Long id);
    int insertClazz(@Param("cid") Integer cid,@Param("cname") String cname);
}
<?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.powernode.mybatis.mappers.CarMapper">
<!--    添加一个cache标签即可-->
    <cache></cache>
    <select id="selectById" resultType="Car">
        select * from t_car where id = #{id}
    </select>
    <insert id="insertClazz">
        insert into t_clazz values(#{cid},#{cname})
    </insert>
    <select id="selectByIdSecondCache" resultType="Car">
        select * from t_car where id = #{id}
    </select>
</mapper>

<?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.powernode.mybatis.mappers.CarMapper">
<!--    添加一个cache标签即可-->
    <cache></cache>
    <select id="selectById" resultType="Car">
        select * from t_car where id = #{id}
    </select>
    <insert id="insertClazz">
        insert into t_clazz values(#{cid},#{cname})
    </insert>
    <select id="selectByIdSecondCache" resultType="Car">
        select * from t_car where id = #{id}
    </select>
</mapper>
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到