Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存

这篇具有很好参考价值的文章主要介绍了Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

缓存越小,查询速度越快,缓存数据越少
缓存越大,查询速度越慢,缓存数据越多

在多级缓存中,一般常见的是先查询一级缓存,再查询二级缓存,但在Mybatis中是先查询二级缓存,再查询一级缓存。

在Mybatis中,BaseExecutor属于一级缓存执行器,CachingExecutor属于二级缓存执行器,二者采用了装饰器设计模式。

一级缓存:默认情况下一级缓存是开启的,而且是不能关闭的,一级缓存是指SqlSession级别的缓存,当在同一个SqlSession中使用相同的SQL语句进行查询时,第二次以及之后的查询都不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存1024条SQL。
二级缓存:二级缓存是指可以跨SqlSession的缓存。是mapper级别的缓存,对于mapper级别的缓存不同的SqlSession是可以共享的,需要额外整合第三方缓存,例如Redis、MongoDB、oscache、ehcache等。

注:本文代码演示基于《Mybatis环境搭建与使用》中的“基于XML方式-mapper代理开发”的代码进行调整。

一级缓存

特点

一级缓存也叫本地缓存,在Mybatis中,一级缓存是在会话层面(SqlSession)实现的,这就说明一级缓存的作用范围只能在同一个SqlSession中,在多个不同的SqlSession中是无效的。

在Mybatis中,一级缓存是默认开启的,不需要任何额外的配置。

演示前准备

为了能够看到演示的效果,需要在mybatis-config.xml文件中加上以下配置

<settings>
    <!-- 打印sql日志 -->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

效果演示

在同一个SqlSession中

MybatisTest03.java

package com.mybatis.test;

import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
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;
import java.util.List;

/**
 * @author honey
 * @date 2023-08-01 16:23:53
 */
public class MybatisTest03 {

    public static void main(String[] args) throws IOException {
        // 1.读取加载mybatis-config.xml(数据源、mybatis等配置)
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 2.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3.根据mapper(namespace="UserMapper全限定名" + id="listUser")执行sql语句,并将查询到的数据映射成对象(orm)
        UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);
        System.out.println("【一级缓存-在同一个SqlSession中】第一次查询");
        List<UserEntity> list1 = mapper1.listUser();
        System.out.println("list1:" + list1);

        UserMapper mapper2 = sqlSession.getMapper(UserMapper.class);
        System.out.println("【一级缓存-在同一个SqlSession中】第二次查询");
        List<UserEntity> list2 = mapper2.listUser();
        System.out.println("list2:" + list2);

        sqlSession.close();
    }
}

运行上面的代码可以看到,在同一个SqlSession中,第二次查询是没有去查询数据库的,而是直接读取的缓存数据。

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

源码Debug分析

BaseExecutor.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存
Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

在不同的SqlSession中

MybatisTest04.java

package com.mybatis.test;

import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
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;
import java.util.List;

/**
 * @author honey
 * @date 2023-08-01 16:23:53
 */
public class MybatisTest04 {

    public static void main(String[] args) throws IOException {
        // 1.读取加载mybatis-config.xml(数据源、mybatis等配置)
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 2.获取sqlSession
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        // 3.根据mapper(namespace="UserMapper全限定名" + id="listUser")执行sql语句,并将查询到的数据映射成对象(orm)
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        System.out.println("【一级缓存-在不同的SqlSession中】第一次查询");
        List<UserEntity> list1 = mapper1.listUser();
        System.out.println("list1:" + list1);

        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        System.out.println("【一级缓存-在不同的SqlSession中】第二次查询");
        List<UserEntity> list2 = mapper2.listUser();
        System.out.println("list2:" + list2);

        sqlSession1.close();
        sqlSession2.close();
    }
}

运行上面的代码可以看到,在不同的SqlSession中,两次查询都是查询的数据库,也就是说一级缓存并没有生效。

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

源代码

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存
Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

怎么禁止使用一级缓存

  1. 在SQL语句上加上随机生成的参数;(不推荐)
  2. 开启二级缓存;
  3. 使用SqlSession强制清除缓存;
  4. 每次查询都使用新的SqlSession;
  5. 通过配置清除缓存;

一级缓存在什么情况下会被清除

  1. 提交事务/回滚事务/强制清除缓存
sqlSession.commit();
sqlSession.rollback();
sqlSession.clearCache()

以提交事务为例,回滚事务/强制清除缓存同理

MybatisTest03.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

DefaultSqlSession.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

BaseExecutor.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存
Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 在执行insert、update、delete语句时

BaseExecutor.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 使用配置清除一级缓存
<!-- 设置一级缓存作用域 -->
<setting name="localCacheScope" value="STATEMENT"/>

mybatis-config.xml

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

BaseExecutor.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

二级缓存

特点

二级缓存是mapper级别的缓存,通过整合第三方缓存实现,二级缓存的作用范围可以在不同的SqlSession中。

在Mybatis中,二级缓存默认是开启的,但还需要做一些额外的配置才能生效。

演示前准备

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 启动Redis

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 添加pom依赖

pom.xml

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.0.1</version>
</dependency>
  1. 实现Cache类

RedisCache.java

package com.mybatis.cache;

import com.mybatis.utils.SerializeUtil;
import org.apache.ibatis.cache.Cache;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author honey
 * @date 2023-08-01 23:44:10
 */
public class RedisCache implements Cache {

    private final Jedis redisClient = createRedis();

    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private final String id;

    public RedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        this.id = id;
    }


    @Override
    public String getId() {
        return id;
    }

    @Override
    public void putObject(Object key, Object value) {
        System.out.printf("【存入缓存数据】key:%s,value:%s%n", key, value);
        redisClient.set(SerializeUtil.serialize(key), SerializeUtil.serialize(value));
    }

    @Override
    public Object getObject(Object key) {
        byte[] bytes = redisClient.get(SerializeUtil.serialize(key));
        if (bytes == null) {
            return null;
        }
        Object value = SerializeUtil.deserialize(bytes);
        System.out.printf("【读取缓存数据】key:%s,value:%s%n", key, value);
        return value;
    }

    @Override
    public Object removeObject(Object key) {
        return redisClient.expire(String.valueOf(key), 0);
    }

    @Override
    public void clear() {
        redisClient.flushDB();
    }

    @Override
    public int getSize() {
        return Integer.parseInt(redisClient.dbSize().toString());
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }

    protected static Jedis createRedis() {
        JedisPool pool = new JedisPool("127.0.0.1", 6379);
        return pool.getResource();
    }
}

SerializeUtil.java

package com.mybatis.utils;

import java.io.*;

/**
 * @author honey
 * @date 2023-08-02 00:50:37
 */
public class SerializeUtil {

    public static byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(oos);
            close(baos);
        }
        return null;
    }

    public static Object deserialize(byte[] bytes) {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(bais);
            close(ois);
        }
        return null;
    }

    /**
     * 关闭io流对象
     *
     * @param closeable closeable
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

注意:UserEntity需要实现序列化接口

UserEntity.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 添加配置(userMapper.xml)

userMapper.xml

<cache eviction="LRU" type="com.mybatis.cache.RedisCache"/>

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

效果演示

在不同的SqlSession中

MybatisTest05.java

package com.mybatis.test;

import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
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;
import java.util.List;

/**
 * @author honey
 * @date 2023-08-01 16:23:53
 */
public class MybatisTest05 {

    public static void main(String[] args) throws IOException {
        // 1.读取加载mybatis-config.xml(数据源、mybatis等配置)
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 2.获取sqlSession
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        // 3.根据mapper(namespace="UserMapper全限定名" + id="listUser")执行sql语句,并将查询到的数据映射成对象(orm)
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        System.out.println("【二级缓存-在不同的SqlSession中】第一次查询");
        List<UserEntity> list1 = mapper1.listUser();
        System.out.println("list1:" + list1);

        sqlSession1.close();

        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        System.out.println("【二级缓存-在不同的SqlSession中】第二次查询");
        List<UserEntity> list2 = mapper2.listUser();
        System.out.println("list2:" + list2);

        sqlSession2.close();
    }
}

运行上面的代码可以看到,在不同的SqlSession中,第一次查询读取的是数据库中的数据,而第二次查询读取的是缓存中的数据。

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

注意:查询到的数据并不是在第一时间就存入缓存,而是在提交事务(sqlSession1.close())的时候才存入缓存。

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

源代码

CachingExecutor.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

TransactionalCacheManager.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存


根据Cache(id=“mapper全限定名”)获取对应的TransactionalCache对象,并将数据临时存放在该对象中。

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存


TransactionalCache.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

在执行sqlSession1.close()这行代码时,会将临时存放的数据存入缓存。

DefaultSqlSession.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

CachingExecutor.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 如果是提交事务,则会先将临时存放的数据存入缓存,再将临时存放的数据清空

TransactionalCacheManager.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

TransactionalCache.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

  1. 如果是回滚事务,则只会将临时存放的数据清空

TransactionalCacheManager.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

TransactionalCache.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

怎么关闭二级缓存

修改配置文件(mybatis-config.xml)

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

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

一级缓存(Spring整合Mybatis)

在未开启事务的情况下,每次查询Spring都会关闭旧的SqlSession而创建新的SqlSession,因此此时的一级缓存是没有生效的;
在开启事务的情况下,Spring模板使用threadLocal获取当前资源绑定的同一个SqlSession,因此此时一级缓存是有效的;

演示前准备

项目结构

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

pom.xml

<?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</groupId>
    <artifactId>springboot-mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

application.yml

server:
  port: 8080

spring:
  datasource:
    username: root
    password: admin
    url: jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      connection-timeout: 10000

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.mybatis.mapper.UserMapper">
    <select id="listUser" resultType="com.mybatis.entity.UserEntity">
        select * from tb_user
    </select>
</mapper>

AppMybatis.java

package com.mybatis;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author honey
 * @date 2023-08-02 02:58:16
 */
@SpringBootApplication
public class AppMybatis {

    public static void main(String[] args) {
        SpringApplication.run(AppMybatis.class);
    }
}

UserEntity.java

package com.mybatis.entity;

import lombok.Data;

/**
 * @author honey
 * @date 2023-08-02 03:03:19
 */
@Data
public class UserEntity {

    private Long id;

    private String name;
}

UserMapper.java

package com.mybatis.mapper;

import com.mybatis.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @author honey
 * @date 2023-07-26 21:04:23
 */
@Mapper
public interface UserMapper {

    /**
     * 查询用户列表
     *
     * @return List<UserEntity>
     */
    List<UserEntity> listUser();
}

UserController.java

package com.mybatis.controller;

import com.mybatis.entity.UserEntity;
import com.mybatis.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author honey
 * @date 2023-08-02 03:09:13
 */
@RestController
@RequiredArgsConstructor
public class UserController {

    private final UserMapper userMapper;

    @RequestMapping("listUser")
    public void listUser(){
        List<UserEntity> list = userMapper.listUser();
        System.out.println(list);
    }
}

效果演示

不开启事务,调用多次接口

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第一次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第二次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

两次调用获取到的是不同的SqlSession,一级缓存不生效

开启事务,调用多次接口

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第一次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第二次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

两次调用获取到的也是不同的SqlSession,一级缓存不生效

不开启事务,接口中多次调用查询方法

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第一次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第二次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

两次调用获取到的依然是不同的SqlSession,一级缓存不生效

开启事务,接口中多次调用查询方法

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第一次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

第二次调用

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

两次调用获取到的是相同的SqlSession,一级缓存生效

总结

只有在同一个事务内执行查询,一级缓存才会生效。

源代码

MapperMethod.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

在Spring整合Mybatis的代码中,新增了SqlSessionTemplate类对DefaultSqlSession类的功能进行增强。

SqlSessionTemplate.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

SqlSessionUtils.java

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存,mybatis,mr,mybatis,缓存

能获取到SqlSessionHolder对象的前提是开启了事务。如果当前线程开启了事务,则不会直接关闭SqlSession对象,而是在下一次调用时复用SqlSession对象。文章来源地址https://www.toymoban.com/news/detail-624506.html

到了这里,关于Mr. Cappuccino的第55杯咖啡——Mybatis一级缓存&二级缓存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Mr. Cappuccino的第64杯咖啡——Spring循环依赖问题

    多个bean之间相互依赖,形成了一个闭环。 比如:A依赖于B、B依赖于C、C依赖于A 通常来说,如果问Spring容器内部如何解决循环依赖问题,一定是指默认的单例Bean中,属性相互引用的场景。也就是说,Spring的循环依赖,是Spring容器注入时出现的问题。 示例 项目结构 项目代码

    2024年02月11日
    浏览(25)
  • Mr. Cappuccino的第68杯咖啡——基于Docker安装Oracle11g

    拉取镜像 以持久化的方式启动容器 关于持久化,source=oracle_vol指的是容器中的数据卷路径,target指的是容器外需要被挂载的目录路径。 查看volume的具体位置 修改配置文件 使用I键进入编辑模式,添加以下配置信息,再使用Esc键退出编辑模式,输入:wq保存配置信息。 检查配置

    2024年01月17日
    浏览(41)
  • Mr. Cappuccino的第60杯咖啡——Spring之BeanFactory和ApplicationContext

    概述 BeanFactory,以Factory结尾,表示它是一个工厂类(接口), 它是负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖; BeanFactory只是个接口,并不是IOC容器的具体实现,但是

    2024年02月13日
    浏览(27)
  • Mr. Cappuccino的第62杯咖啡——Spring之Bean的生命周期

    实现Aware接口是为了bean能获取某些信息、感知某些信息。Aware自身是一个空的接口,Spring提供了很多它的实现接口,开发者实现这些已有的接口就能获取特定的一些信息。 Spring提供了一些Aware接口的实现接口: ApplicationContextAware、ApplicationEventPublisherAware、BeanClassLoaderAware、Be

    2024年02月12日
    浏览(23)
  • Mr. Cappuccino的第58杯咖啡——MacOS配置Maven和Java环境

    如果使用的是bash,则使用以下命令 因为我这里使用的是zsh,所以使用以下命令 下载Maven Maven下载地址 配置前准备 使用command+shift+G进入/usr/local/目录 创建maven文件夹 将下载好的Maven压缩包解压 把解压后的文件复制到maven文件夹下面,并创建repo文件夹用来存放拉取的maven依赖

    2024年02月14日
    浏览(32)
  • Mr. Cappuccino的第63杯咖啡——Spring之AnnotationConfigApplicationContext源码分析

    以上一篇文章《Spring之Bean的生命周期》的代码进行源码分析 AnnotationConfigApplicationContext.java AbstractApplicationContext.java BeanFactory中两个重要的对象 DefaultListableBeanFactory.java DefaultSingletonBeanRegistry.java Debug源码分析 register(componentClasses):注册指定的配置类SpringConfig02到beanDefinitionMap集

    2024年02月13日
    浏览(24)
  • Mybatis 一级缓存和二级缓存 与hibernate 一级缓存和二级缓存 有什么区别?

    MyBatis和Hibernate都是流行的持久化框架,它们都提供了一级缓存和二级缓存的功能,但在实现和使用上有一些区别。 一级缓存: - MyBatis的一级缓存是默认开启的,它是在SqlSession级别的缓存,也就是在同一个SqlSession中,如果多次查询同样的SQL语句,那么只会执行一次数据库查

    2024年02月15日
    浏览(23)
  • Mybatis学习|Mybatis缓存:一级缓存、二级缓存

    MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。 MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存) 二级缓存需要手动开启和配置,他是

    2024年02月09日
    浏览(25)
  • MyBatis的缓存,一级缓存,二级缓存

    10.1、MyBatis的一级缓存 一级缓存是SqlSession级别的,通过 同一个 SqlSession对象 查询的结果数据会被缓存,下次执行 相同的查询语句 ,就 会 从缓存中(缓存在内存里) 直接获取,不会重新访问数据库(数据库在磁盘里),也就是说就执行一次sql。一级缓存 默认开启 。 使一级

    2024年02月07日
    浏览(34)
  • Mybatis缓存机制(一级缓存、二级缓存、三级缓存)

    缓存就是内存中的数据,常常来自对数据库查询结果的保存。 使用缓存,我们可以避免频繁与数据库进行交互,从而提高响应速度。 Mybatis的缓存分为一级缓存、二级缓存、三级缓存。 一级缓存: 作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句, 第一

    2024年02月05日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包