当前位置: 首页 > article >正文

Java的缓存

目录

MyBatis的缓存机制

一级缓存(SqlSession级别)

二级缓存(全局级别)

Mapper 级别和 namespace 级别的关系

Spring的缓存机制

2.1 Redis 在 Spring 中的集成

2.2 Caffeine 在 Spring 中的集成

2.3EhCache 在 Spring 中的集成

SpringBoot的缓存机制

Redis 在 SpringBoot 中的集成

1. 添加依赖

2. 配置 Redis

3. 启用缓存

4. 配置 RedisTemplate(可选)

5. 编写 Redis 操作类

6. 使用 Redis

MYSQL 的缓存机制

1. 查询缓存(Query Cache)

特点

配置

2. InnoDB 缓冲池(Buffer Pool)

特点

配置

3. MyISAM 缓存

特点

配置

4. 二进制日志缓存(Binary Log Cache)

特点

配置

5. 临时表缓存(Temporary Table Cache)

特点

配置

6. 表缓存(Table Cache)

特点

配置

mysql的缓存机制

1. 查询缓存(Query Cache)

2. InnoDB 缓冲池(Buffer Pool)

3. MyISAM 缓存

4. 二进制日志缓存(Binary Log Cache)

5. 临时表缓存(Temporary Table Cache)

6. 表缓存(Table Cache)

Java 本身的缓存

1. 常量池(Constant Pool)

2. String.intern()

3. HashMap 或其他集合

4. WeakHashMap

5. SoftReference 和 WeakReference

6. java.util.concurrent 包

7. 设计模式:单例模式

8. Java 缓存库


先来看

MyBatis的缓存机制

MyBatis提供了两级缓存机制,一级缓存(SqlSession级别)和二级缓存(全局级别),以通过减少数据库的查询次数来提高应用的性能。

一级缓存(SqlSession级别)

一级缓存是MyBatis默认开启且无法关闭的缓存,作用范围是SqlSession级别(SQL会话==SqlSession)

  • 作用范围:仅限于同一个SqlSession实例。
  • 默认开启:无需任何配置。
  • 生命周期:与SqlSession一致,SqlSession关闭时,一级缓存清空。
  • 失效条件
    • 执行insertupdatedelete操作时,一级缓存会被清空。
    • 调用SqlSession.clearCache()方法手动清空。
  • 存储位置:默认存储在 JVM 内存中,通过 HashMap 实现

在同一个 SQL 会话中,对于相同的查询请求,第一次会从数据库中获取数据,并缓存结果,之后相同的查询请求将直接从缓存中获取数据,不会再去访问数据库。

try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user1 = mapper.getUserById(1); // 查询数据库
    User user2 = mapper.getUserById(1); // 从一级缓存获取
    System.out.println(user1 == user2); // true
}

二级缓存(全局级别)

二级缓存是跨SQL 会话的共享缓存,作用范围是Mapper级别,需要手动配置。

开启二级缓存后,数据会存储在全局作用域内,这意味着,即使 SQL 会话关闭,缓存数据仍然可用,可以被其他 SQL 会话复用。

  • 作用范围:同一个Mapper的多个SqlSession共享。
  • 手动配置:默认关闭,需在mybatis-config.xmlMapper.xml中配置。
  • 缓存实现:默认使用内存缓存,也可集成Redis等外部缓存。
  • 失效条件:在Mapper中执行insertupdatedelete操作时,二级缓存会被清空。
  • 存储位置
    • 默认存储在 JVM 内存中。
    • 可以通过配置集成外部缓存,如 EhCache 或 Redis。

也有的说二级缓存的作用范围是 namespace 级别的,但其实namespace 级别和Mapper级别这两种说法本质上是相同的,只是表述方式不同。

Mapper 级别和 namespace 级别的关系

  • Mapper级别:指的是同一个 Mapper接口或 Mapper XML 文件的作用范围。在 MyBatis 中,每个 Mapper 接口或 XML 文件都有一个唯一的 namespace
  • namespace级别:namespaceMapper 的唯一标识,通常对应一个 Mapper 接口或 XML 文件。二级缓存的作用范围是基于 namespace 的,这意味着同一个 namespace 下的所有操作共享同一个缓存。

所以,Mapper 级别和namespace级别在 MyBatis 二级缓存中是等价的,都是指同一个 Mapper 的所有操作共享缓存。

二级缓存配置

  1. mybatis-config.xml中启用二级缓存:
<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>
  1. Mapper.xml中配置二级缓存:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
  • eviction:缓存回收策略常用的有:
    • FifoCache:先进先出。
    • LruCache:最近最少使用。
    • SoftCache:基于软引用的缓存。
    • WeakCache:基于弱引用的缓存。
  • flushInterval:缓存刷新间隔(毫秒),每隔指定时间,缓存中的数据会被清空。
  • size:缓存对象的最大数量。
  • readOnly:是否只读(true表示只读,缓存对象不会被修改)。
  • implementation:缓存实现类。默认是 PerpetualCache,也可以指定其他实现(如集成 Redis)。

  1. 在 Mapper 接口上添加 @CacheNamespace 注解:
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.decorators.FifoCache;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.annotations.CacheNamespace;

@CacheNamespace(
    eviction = FifoCache.class,       // 缓存回收策略:先进先出
    flushInterval = 60000,           // 缓存刷新间隔:60000 毫秒(60秒)
    size = 512,                      // 缓存对象的最大数量:512
    readWrite = false                // 是否可读写:false 表示只读
)
public interface UserMapper {
    User getUserById(int id);
    void updateUser(User user);
}
  1. 确保实体类实现 Serializable 接口:

由于二级缓存会将数据存储到外部存储(如内存缓存或分布式缓存),因此缓存的对象必须实现 Serializable 接口。

import java.io.Serializable;

public class User implements Serializable {
    private int id;
    private String name;
    private String email;

    // Getter 和 Setter 方法
}

try (SqlSession session1 = sqlSessionFactory.openSession()) {
    UserMapper mapper = session1.getMapper(UserMapper.class);
    User user1 = mapper.getUserById(1); // 查询数据库并存入二级缓存
}
try (SqlSession session2 = sqlSessionFactory.openSession()) {
    UserMapper mapper = session2.getMapper(UserMapper.class);
    User user2 = mapper.getUserById(1); // 从二级缓存获取
    System.out.println(user1 == user2); // true
}

  • 注解优先级高于 XML 配置: 如果同时在 Mapper 接口和 Mapper XML 文件中配置了二级缓存,注解的配置会优先生效。
  • 缓存对象序列化: 二级缓存中存储的对象必须实现 Serializable 接口,否则可能会抛出序列化异常。
  • 事务管理: 在事务提交后,查询结果才会被存储到二级缓存中。如果事务回滚,缓存不会被更新。
  • 缓存失效: 当执行 INSERTUPDATEDELETE 操作时,二级缓存会被清空,以保证数据一致性。
  • 适用场景
    • 查询操作多,增删改操作少。
    • 业务以单表操作为主,表间关联较少

一级缓存 和 二级缓存 区别

1. 作用范围

缓存类型

作用范围

一级缓存

单个 SqlSession级别。同一个 SqlSession内的查询共享一级缓存。

二级缓存

Mapper级别(namespace级别)。同一个 Mapper的不同 SqlSession共享二级缓存。

2. 生命周期

缓存类型

生命周期

一级缓存

生命周期与 SqlSession一致。SqlSession关闭时,一级缓存清空。

二级缓存

生命周期独立于 SqlSession。二级缓存数据会一直存在,直到显式清空或达到缓存策略的限制(如时间间隔、大小限制)。

3. 配置方式

缓存类型

配置方式

一级缓存

默认开启,无法关闭。无需任何配置。

二级缓存

需要手动配置。可以在 Mapper接口上使用 @CacheNamespace注解,或在 Mapper.xml文件中配置 <cache>标签。

4. 缓存失效条件

缓存类型

失效条件

一级缓存

  • 执行 insertupdatedelete操作;
  • 调用 SqlSession.clearCache()
  • SqlSession关闭。

二级缓存

  • 执行 insertupdatedelete操作;
  • 达到缓存策略限制(如时间间隔、大小限制);
  • 显式调用清空缓存的方法。

5. 数据共享性

缓存类型

数据共享性

一级缓存

不支持跨 SqlSession共享。

二级缓存

支持跨 SqlSession共享。

6. 使用场景

缓存类型

适用场景

一级缓存

适用于单个 SqlSession内的重复查询。

二级缓存

适用于跨 SqlSession的重复查询,尤其是读多写少的场景。

7. 缓存数据存储

缓存类型

存储方式

一级缓存

存储在内存中,与 SqlSession绑定。

二级缓存

默认存储在内存中,但可以集成外部缓存(如 Redis)。

简写:

特性

一级缓存

二级缓存

作用范围

单个 SqlSession

SqlSessionMapper级别)

生命周期

SqlSession一致

独立于 SqlSession

配置方式

默认开启,无需配置

需手动配置(注解或 XML)

失效条件

执行增删改操作、SqlSession关闭等

执行增删改操作、达到缓存策略限制等

数据共享性

不支持跨 SqlSession共享

支持跨 SqlSession共享

适用场景

单个 SqlSession内的重复查询

SqlSession的重复查询,读多写少的场景

存储方式

内存存储

内存存储或外部缓存(如 Redis)

Spring的缓存机制

Spring 本身没有内置的缓存实现,而是通过缓存抽象层与各种缓存框架集成。

开发者可以根据需求选择基于 JVM 的缓存(如 Caffeine、EhCache)或第三方分布式缓存(如 Redis、Memcached)。

这种设计使得 Spring 的缓存功能非常灵活,能够适应不同的应用场景和性能需求。

Spring 的缓存抽象层是一个通用的缓存框架,它定义了缓存操作的接口(如 CacheCacheManager,springboot会详细讲到),但具体的缓存实现需要通过第三方库或基于 JVM 的缓存来提供。

Spring 支持的缓存类型:

根据缓存的存储位置和实现方式,Spring 支持的缓存可以分为以下几类:

1. 基于 JVM 的缓存

这些缓存完全运行在 Java 虚拟机内存中,不需要外部服务。

常见的基于 JVM 的缓存包括:

  • Simple(简单缓存):Spring 提供的默认缓存实现,基于 ConcurrentHashMap,适合简单的应用场景。
  • Caffeine:高性能的本地缓存库,支持多种缓存策略(如 LRU、TTL 等)。
  • EhCache:功能丰富的本地缓存框架,支持内存和磁盘存储,以及缓存的持久化。
  • Guava Cache:Google 提供的本地缓存库,适合简单的缓存需求。

2. 第三方分布式缓存

这些缓存运行在独立的服务器上,支持分布式环境,适合高并发和大规模数据存储。常见的分布式缓存包括:

  • Redis:高性能的分布式缓存系统,支持多种数据结构(如字符串、列表、哈希等)。
  • Memcached:轻量级的分布式缓存系统,适合存储简单的键值对数据。
  • Hazelcast:支持内存数据网格的分布式缓存系统。

本文着重Redis、Caffeine 和 EhCache 在 Sprig 项目中的集成。

2.1 Redis 在 Spring 中的集成

Redis 是一个独立的缓存服务器,需要在服务器或本地单独安装和运行。

  1. 安装 Redis:
    • 在服务器上安装 Redis,并确保其运行在某个端口上(默认是 6379)。
    • 配置 Redis 的 redis.conf 文件(可选)。
  1. 在 Spring 项目中集成 Redis:
    • 添加依赖(使用 Maven):
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>你的版本号</version>
</dependency>
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>你的版本号</version>
</dependency>

配置 Redis 连接工厂和 RedisTemplate

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory("localhost", 6379);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        return template;
    }
}

使用 RedisTemplate

@Service
public class RedisService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }
}

在 Spring 项目中使用 Redis 时,需要配置 RedisConnectionFactoryRedisTemplate,并通过这些组件与 Redis 服务器进行交互。

2.2 Caffeine 在 Spring 中的集成

Caffeine 是一个本地缓存库,完全运行在 JVM 内存中,不需要单独安装任何服务。

Caffeine 在 Spring 中的缓存是存储在 JVM 内存中的。Caffeine 是一个高性能的本地缓存库,它的设计目标是提供快速、低延迟的缓存服务,适用于单机应用。

Caffeine 缓存存储在 JVM 内存中的特点

  1. 高性能:由于缓存数据存储在本地 JVM 内存中,访问速度非常快,适合对性能要求较高的场景。
  2. 本地缓存:每个应用实例都有自己的缓存空间,缓存数据仅对当前应用实例可见。
  3. 内存限制:缓存的大小受限于 JVM 的可用内存,可以通过配置最大容量来避免内存溢出


1. 添加依赖:

<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
  <version>你的版本号</version>
</dependency>

2.配置 CaffeineCacheManager:

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class CaffeineConfig {
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("myCache");
        cacheManager.setCaffeine(Caffeine.newBuilder()
                                 .expireAfterWrite(10, TimeUnit.MINUTES)
                                 .maximumSize(1000));
        return cacheManager;
    }
}

3.使用缓存:
 

@Service
public class MyService {
    @Cacheable(value = "myCache", key = "#id")
    public String getData(String id) {
        return "My ID: " + id;
    }
}

Caffeine 是一个纯 Java 缓存库,运行在 JVM 内存中。

在 Spring 项目中使用 Caffeine 时,只需要添加依赖并配置 CaffeineCacheManager,无需任何外部服务。

2.3EhCache 在 Spring 中的集成

EhCache 是一个本地缓存框架,支持内存和磁盘存储,同样不需要单独安装任何服务。

在 Spring 中使用 EhCache 时,缓存数据的存储位置取决于 EhCache 的配置方式。EhCache 支持多种存储策略,包括内存(堆内)、堆外内存(off-heap)以及磁盘存储。

  1. 堆内内存(Heap):
    • 缓存数据存储在 JVM 的堆内存中。
    • 适用于缓存数据量较小且对性能要求较高的场景。
  1. 堆外内存(Off-Heap):
    • 缓存数据存储在 JVM 堆外内存中。
    • 堆外内存不属于 JVM 的堆空间,因此可以避免垃圾回收(GC)的干扰。
    • 数据需要序列化后存储,读取时需要反序列化。
  1. 磁盘存储(Disk):
    • 缓存数据可以溢出到磁盘,支持持久化。
    • 可以在应用重启后恢复缓存数据。
    • 配置磁盘存储路径时,可以指定一个目录来存储缓存文件。

1.添加依赖:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>你的版本号</version>
</dependency>
<dependency>
  <groupId>org.ehcache</groupId>
  <artifactId>ehcache</artifactId>
  <version>你的版本号</version>
</dependency>

2.配置 EhCache:

  • 创建 ehcache.xml 配置文件:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
  <cache name="myCache"
    maxEntriesLocalHeap="1000"
    eternal="false"
    timeToIdleSeconds="300"
    timeToLiveSeconds="600">
  </cache>
</ehcache>

配置 EhCacheCacheManager

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
@EnableCaching
public class EhCacheConfig {
    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
        EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
        cacheManagerFactoryBean.setShared(true);
        return cacheManagerFactoryBean;
    }

    @Bean
    public CacheManager cacheManager(EhCacheManagerFactoryBean ehCacheManagerFactoryBean) {
        return new EhCacheCacheManager(ehCacheManagerFactoryBean.getObject());
    }
}

3.使用缓存:

@Service
public class MyService {
    @Cacheable(value = "myCache", key = "#id")
    public String getData(String id) {
        return "Data for ID: " + id;
    }
}

EhCache 是一个本地缓存框架,支持内存和磁盘存储。

在 Spring 项目中使用 EhCache 时,需要添加依赖并配置 EhCacheCacheManager,无需任何外部服务。

SpringBoot的缓存机制

和 Spring 一样,都是通过Spring Cache 抽象层 来实现缓存功能。

Spring Cache 抽象层是一个通用的缓存框架,它提供了一组标准的缓存接口和注解,使得开发者可以轻松地将缓存功能集成到应用程序中,而无需关心具体的缓存实现。

Spring Cache 抽象层的核心组件包括:

  1. @EnableCaching:用于启用缓存功能的注解,通常添加在配置类或主类上。
  2. @Cacheable:用于标记方法的返回值可以被缓存。
  3. @CachePut:用于更新缓存中的数据。
  4. @CacheEvict:用于清除缓存中的数据。
  5. CacheManager:负责管理多个缓存实例。
  6. Cache:定义了缓存的基本操作接口。

虽然 Spring 和 Spring Boot 都使用了 Spring Cache 抽象层,但它们在 配置方式和默认行为 上有所不同:

1. Spring(非 Spring Boot)

在传统的 Spring 应用程序中:

  • 没有内置的缓存实现:Spring Cache 抽象层本身不提供具体的缓存实现。
  • 需要手动配置:开发者需要手动配置 CacheManager 和具体的缓存实现(如 EhCache、Caffeine 等)。
@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager() {
        // 配置 EhCache 或 Caffeine 等具体缓存实现
        return new EhCacheCacheManager(ehCacheManagerFactory().getObject());
    }
}

2. Spring Boot

Spring Boot 在 Spring Cache 抽象层的基础上进行了简化和自动配置:

  • 内置的默认缓存实现:如果没有显式配置任何缓存实现,Spring Boot 会自动启用一个基于 ConcurrentHashMap 的简单缓存实现(SimpleCacheManagerConcurrentMapCacheManager)。这可以看作是 Spring Boot 提供的“内置”缓存实现,但它仍然是基于 Spring Cache 抽象层的。
  • 自动配置:Spring Boot 会根据添加的依赖自动选择合适的缓存实现。例如:
    • 如果添加了 Caffeine 的依赖,Spring Boot 会自动配置 CaffeineCacheManager
    • 如果添加了 Redis 的依赖,Spring Boot 会自动配置 RedisCacheManager
<!-- 添加 Caffeine 依赖 -->
<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
</dependency>
@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

总结:Spring 和 Spring Boot 的缓存机制

  1. Spring Cache 抽象层 是 Spring 框架的一部分,提供了一套通用的缓存接口和注解,但本身不提供具体的缓存实现。
  2. Spring(非 Spring Boot):
    • 没有内置的缓存实现。
    • 需要手动配置 CacheManager 和具体的缓存实现。
  1. Spring Boot:
    • 提供了一个基于 ConcurrentHashMap 的简单默认缓存实现(ConcurrentMapCacheManager)。
    • 根据添加的依赖自动配置更强大的缓存实现(如 Caffeine、Redis 等)。
    • 这种自动配置机制使得 Spring Boot 的缓存功能看起来像是“内置”的,但实际上它仍然是基于 Spring Cache 抽象层的。

Spring 和 Spring Boot 的缓存抽象层对比

特性

Spring

Spring Boot

配置方式

手动配置 CacheManager和缓存实现

自动配置,通过添加依赖启用缓存功能

默认缓存实现

无默认实现,需手动指定

默认使用 ConcurrentHashMap

集成第三方缓存

手动添加依赖并配置

添加依赖后自动配置,支持多种缓存实现

注解支持

支持 @Cacheable@CachePut@CacheEvict

支持相同的注解,但配置更简化

灵活性

高度灵活,适合复杂配置

简化配置,适合快速开发

也就是 Spring 和 Spring Boot,都通过 Spring Cache 抽象层 提供缓存功能。

而Spring Boot 在此基础上进行了简化和自动配置,使得开发者可以更轻松地启用和集成缓存,而无需手动配置复杂的 CacheManager 和缓存实现。
 

SpringBoot的缓存机制属于是:

  • 开箱即用:即使没有显式配置任何缓存实现,Spring Boot 也会提供一个基于内存的简单缓存(默认使用 ConcurrentHashMap)。这种缓存适合简单的开发场景或轻量级的生产环境。
  • 灵活性:在需要更强大的缓存功能时,Spring Boot 可以轻松集成第三方缓存解决方案(如 Caffeine、EhCache、Redis 等)。
  • 自动配置:Spring Boot 通过 spring-boot-starter-cache 模块自动配置缓存功能。它会根据项目中添加的依赖自动选择合适的缓存实现。
    • 如果没有添加任何缓存依赖,Spring Boot 会启用默认的内存缓存。
    • 如果添加了第三方缓存依赖(如 Caffeine 或 Redis),Spring Boot 会自动配置相应的缓存实现。
  • 简化配置:开发者只需添加依赖并启用缓存功能(通过 @EnableCaching),而无需手动配置复杂的 CacheManager

Redis 在 SpringBoot 中的集成

1. 添加依赖

在项目的 pom.xml 文件中添加 Spring Boot 提供的 Redis 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

如果需要更高级的 Redis 功能(如分布式锁),可以添加 Redisson 的依赖:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.17.0</version> <!-- 请根据需要选择合适的版本 -->
</dependency>

2. 配置 Redis

application.ymlapplication.properties 文件中配置 Redis 的连接信息。

application.yml 示例:

spring:
  redis:
    host: 127.0.0.1  # Redis 服务器地址
    port: 6379       # Redis 服务器端口
    password:        # Redis 密码(如果有)
    database: 0      # 数据库索引(默认为0)
    timeout: 1800000 # 连接超时时间(毫秒)
    lettuce:
      pool:
        max-active: 20  # 连接池最大连接数
        max-wait: -1    # 最大阻塞等待时间(负数表示无限制)
        max-idle: 5     # 最大空闲连接数
        min-idle: 0     # 最小空闲连接数

3. 启用缓存

在主应用类上添加 @EnableCaching 注解:

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. 配置 RedisTemplate(可选)

如果需要操作复杂的数据类型(如对象),可以自定义 RedisTemplate

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer()); // 设置键的序列化器
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // 设置值的序列化器
        return template;
    }
}

5. 编写 Redis 操作类

创建一个服务类来封装 Redis 的常用操作:

@Service
public class RedisService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void setValue(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public Object getValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public void deleteValue(String key) {
        redisTemplate.delete(key);
    }
}

6. 使用 Redis

在业务逻辑中注入 RedisService 或直接使用 RedisTemplate 来操作 Redis。

需要注意的有:

序列化问题:默认情况下,Spring Boot 使用 JdkSerializationRedisSerializer,存储的数据为二进制格式。建议使用 GenericJackson2JsonRedisSerializer 将对象序列化为 JSON 格式,便于调试和监控。

缓存穿透问题:可以通过在缓存中设置空值或使用布隆过滤器来解决。

缓存配置:可以在 spring.cache.redis 下配置缓存相关参数,例如 time-to-livekey-prefix 等。

MYSQL 的缓存机制

MySQL 本身提供了多种缓存机制,用于优化查询性能和减少对磁盘的访问。

1. 查询缓存(Query Cache)

查询缓存是 MySQL 提供的一种缓存机制,用于缓存查询结果。当相同的查询再次执行时,MySQL 可以直接从查询缓存中返回结果,而无需重新执行查询。

特点
  • 缓存查询结果:将查询结果存储在内存中,减少对磁盘的访问。
  • 自动失效:当相关表的数据发生变化时,查询缓存中的相关结果会自动失效。
  • 性能优化:对于重复执行的查询,可以显著提高性能。
配置

查询缓存的大小可以通过以下参数配置:

  • query_cache_size:查询缓存的大小(单位:字节)。
  • query_cache_type:查询缓存的类型(ONOFFDEMAND)。
  • query_cache_limit:单个查询结果的最大缓存大小(单位:字节)。
SET GLOBAL query_cache_size = 1024 * 1024 * 100; -- 100MB
SET GLOBAL query_cache_type = 'ON';
SET GLOBAL query_cache_limit = 1024 * 1024 * 2; -- 2MB

2. InnoDB 缓冲池(Buffer Pool)

InnoDB 缓冲池是 InnoDB 存储引擎的核心缓存机制,用于缓存表数据和索引数据。它显著提高了对表和索引的读写性能。

特点
  • 缓存表数据和索引:将表数据和索引数据存储在内存中,减少对磁盘的访问。
  • LRU 算法:使用最近最少使用(LRU)算法管理缓存数据。
  • 性能优化:对于频繁访问的数据,可以显著提高读写性能。
配置

InnoDB 缓冲池的大小可以通过以下参数配置:

  • innodb_buffer_pool_size:InnoDB 缓冲池的大小(单位:字节)。
  • innodb_buffer_pool_instances:InnoDB 缓冲池的实例数量。

SET GLOBAL innodb_buffer_pool_size = 1024 * 1024 * 1024 * 8; -- 8GB
SET GLOBAL innodb_buffer_pool_instances = 8;

3. MyISAM 缓存

MyISAM 存储引擎也提供了缓存机制,主要用于缓存索引数据。

特点
  • 缓存索引数据:将索引数据存储在内存中,减少对磁盘的访问。
  • 性能优化:对于频繁访问的索引,可以显著提高查询性能。
配置

MyISAM 缓存的大小可以通过以下参数配置:

  • key_buffer_size:MyISAM 缓存的大小(单位:字节)。

SET GLOBAL key_buffer_size = 1024 * 1024 * 100; -- 100MB

4. 二进制日志缓存(Binary Log Cache)

二进制日志缓存用于缓存二进制日志(Binary Log)的写操作,提高写入性能。

特点
  • 缓存二进制日志:将二进制日志的写操作缓存到内存中,减少对磁盘的访问。
  • 性能优化:对于频繁的写操作,可以显著提高性能。
配置

二进制日志缓存的大小可以通过以下参数配置:

  • binlog_cache_size:二进制日志缓存的大小(单位:字节)。

SET GLOBAL binlog_cache_size = 1024 * 1024 * 4; -- 4MB

5. 临时表缓存(Temporary Table Cache)

临时表缓存用于缓存临时表的创建和销毁操作,提高临时表的使用效率。

特点
  • 缓存临时表:将临时表的创建和销毁操作缓存到内存中,减少对磁盘的访问。
  • 性能优化:对于频繁使用的临时表,可以显著提高性能。
配置

临时表缓存的大小可以通过以下参数配置:

  • tmp_table_size:临时表缓存的大小(单位:字节)。
  • max_heap_table_size:内存表(Heap Table)的最大大小(单位:字节)。
SET GLOBAL tmp_table_size = 1024 * 1024 * 100; -- 100MB
SET GLOBAL max_heap_table_size = 1024 * 1024 * 100; -- 100MB

6. 表缓存(Table Cache)

表缓存用于缓存表的打开操作,减少对表的重复打开。

特点
  • 缓存表的打开操作:将表的打开操作缓存到内存中,减少对磁盘的访问。
  • 性能优化:对于频繁访问的表,可以显著提高性能。
配置

表缓存的大小可以通过以下参数配置:

  • table_open_cache:表缓存的大小(单位:表的数量)。


 

SET GLOBAL table_open_cache = 2000;

不过需要注意的是:

  • 查询缓存的限制:查询缓存对 SQL 语句的大小写和空格敏感,且只对 SELECT 查询有效。
  • InnoDB 缓冲池的大小:建议将 innodb_buffer_pool_size 设置为可用内存的 70% 左右,以充分利用内存。
  • MyISAM 缓存的限制:MyISAM 缓存仅对索引数据有效,不缓存表数据。
  • 性能监控:定期监控缓存的使用情况,调整缓存大小以优化性能。

mysql的缓存机制

MySQL 本身提供了多种缓存机制,用于优化查询性能和减少对磁盘的访问。

1. 查询缓存(Query Cache)

查询缓存是 MySQL 提供的一种缓存机制,用于缓存查询结果。当相同的查询再次执行时,MySQL 可以直接从查询缓存中返回结果,而无需重新执行查询。

从 MySQL 5.7 开始,查询缓存的默认开启状态被改为关闭。主要是因为查询缓存存在一些限制和缺陷,可能导致性能问题。

例如,查询缓存对于更新操作(INSERT、UPDATE 和 DELETE)会导致缓存失效,这意味着每次更新后都需要重新执行查询。此外,查询缓存的锁机制在高并发环境下也可能成为性能瓶颈。

特点

  • 缓存查询结果:将查询结果存储在内存中,减少对磁盘的访问。
  • 自动失效:当相关表的数据发生变化时,查询缓存中的相关结果会自动失效。
  • 性能优化:对于重复执行的查询,可以显著提高性能。

查询缓存的大小可以通过以下参数配置:

  • query_cache_size:查询缓存的大小(单位:字节)。
  • query_cache_type:查询缓存的类型(ONOFFDEMAND)。
  • query_cache_limit:单个查询结果的最大缓存大小(单位:字节)。
SET GLOBAL query_cache_size = 1024 * 1024 * 100; -- 100MB
SET GLOBAL query_cache_type = 'ON';
SET GLOBAL query_cache_limit = 1024 * 1024 * 2; -- 2MB

查看查询缓存状态:

SHOW VARIABLES LIKE 'query_cache_type';
SHOW VARIABLES LIKE 'query_cache_size';

2. InnoDB 缓冲池(Buffer Pool)

在 MySQL 5.5.5 之前的版本中,InnoDB 缓冲池并不是默认开启的。从 MySQL 5.5.5 开始,InnoDB 成为默认的存储引擎,InnoDB 缓冲池也随之默认开启。

InnoDB 缓冲池是 InnoDB 存储引擎的核心缓存机制,用于缓存表数据和索引数据。它显著提高了对表和索引的读写性能。

特点

  • 缓存表数据和索引:将表数据和索引数据存储在内存中,减少对磁盘的访问。
  • LRU 算法:使用最近最少使用(LRU)算法管理缓存数据。
  • 性能优化:对于频繁访问的数据,可以显著提高读写性能。

配置

InnoDB 缓冲池的大小可以通过以下参数配置:

  • innodb_buffer_pool_size:InnoDB 缓冲池的大小(单位:字节)。
  • innodb_buffer_pool_instances:InnoDB 缓冲池的实例数量。
SET GLOBAL innodb_buffer_pool_size = 1024 * 1024 * 1024 * 8; -- 8GB
SET GLOBAL innodb_buffer_pool_instances = 8;

3. MyISAM 缓存

MyISAM 存储引擎也提供了缓存机制,主要用于缓存索引数据。

但其是否默认开启和配置可能会因 MySQL 版本和具体安装配置而有所不同。

特点

  • 缓存索引数据:将索引数据存储在内存中,减少对磁盘的访问。
  • 性能优化:对于频繁访问的索引,可以显著提高查询性能。

配置

MyISAM 缓存的大小可以通过以下参数配置:

  • key_buffer_size:MyISAM 缓存的大小(单位:字节)。
SET GLOBAL key_buffer_size = 1024 * 1024 * 100; -- 100MB

4. 二进制日志缓存(Binary Log Cache)

二进制日志缓存用于缓存二进制日志(Binary Log)的写操作,提高写入性能。

特点

  • 缓存二进制日志:将二进制日志的写操作缓存到内存中,减少对磁盘的访问。
  • 性能优化:对于频繁的写操作,可以显著提高性能。

配置

二进制日志缓存的大小可以通过以下参数配置:

  • binlog_cache_size:二进制日志缓存的大小(单位:字节)。
SET GLOBAL binlog_cache_size = 1024 * 1024 * 4; -- 4MB

MySQL 的二进制日志缓存(Binary Log Cache)是否默认开启,取决于 MySQL 的版本和具体配置。

  1. 二进制日志(Binlog)是否默认开启:
    • 在 MySQL 5.7 版本中,二进制日志默认是不开启的。
    • 在 MySQL 8.0 版本中,二进制日志默认是开启的。
  1. 二进制日志缓存(Binary Log Cache):
    • 当二进制日志(Binlog)被开启时,二进制日志缓存(Binary Log Cache)会自动启用。这是因为二进制日志缓存是事务性操作的必要机制。
    • 二进制日志缓存的大小可以通过 binlog_cache_size 参数进行配置。
  1. 如何确认二进制日志是否开启:
    • 可以通过以下命令查看二进制日志是否开启:sql复制
SHOW VARIABLES LIKE 'log_bin';

如果返回值为 ON,则表示二进制日志已开启。

  1. 如何开启二进制日志:
    • 编辑 MySQL 的配置文件(如 my.cnfmy.ini),添加以下配置:ini复制
[mysqld]
log-bin=mysql-bin
    • 重启 MySQL 服务以使配置生效。

5. 临时表缓存(Temporary Table Cache)

临时表缓存用于缓存临时表的创建和销毁操作,提高临时表的使用效率。

特点

  • 缓存临时表:将临时表的创建和销毁操作缓存到内存中,减少对磁盘的访问。
  • 性能优化:对于频繁使用的临时表,可以显著提高性能。

配置

临时表缓存的大小可以通过以下参数配置:

  • tmp_table_size:临时表缓存的大小(单位:字节)。
  • max_heap_table_size:内存表(Heap Table)的最大大小(单位:字节)。


 

SET GLOBAL tmp_table_size = 1024 * 1024 * 100; -- 100MB
SET GLOBAL max_heap_table_size = 1024 * 1024 * 100; -- 100MB

6. 表缓存(Table Cache)

表缓存用于缓存表的打开操作,减少对表的重复打开。

特点

  • 缓存表的打开操作:将表的打开操作缓存到内存中,减少对磁盘的访问。
  • 性能优化:对于频繁访问的表,可以显著提高性能。

配置

表缓存的大小可以通过以下参数配置:

  • table_open_cache:表缓存的大小(单位:表的数量)。

SET GLOBAL table_open_cache = 2000;

需要注意的是:

  • 查询缓存的限制:查询缓存对 SQL 语句的大小写和空格敏感,且只对 SELECT 查询有效。
  • InnoDB 缓冲池的大小:建议将 innodb_buffer_pool_size 设置为可用内存的 70% 左右,以充分利用内存。
  • MyISAM 缓存的限制:MyISAM 缓存仅对索引数据有效,不缓存表数据。
  • 性能监控:定期监控缓存的使用情况,调整缓存大小以优化性能。

Java 本身的缓存

再回到这个问题,Java自己的缓存。

首先,Java 本身并没有一个内置的、通用的缓存机制,但它提供了许多工具和特性,可以用来实现缓存功能。这些工具包括语言特性、标准库中的类,以及一些设计模式。

1. 常量池(Constant Pool)

Java 的常量池是一种特殊的缓存机制,用于存储字符串常量、类和接口的名称、字段名等。常量池是 JVM 的一部分,它确保了字符串常量的唯一性。

String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2); // true,因为它们引用同一个常量池中的对象

2. String.intern()

String.intern() 方法会将字符串存储在常量池中,如果常量池中已经存在相同的字符串,则返回常量池中的引用。这可以看作是一种简单的缓存机制。

String str1 = new String("Hello");
String str2 = new String("Hello").intern();
System.out.println(str1 == str2); // false,因为 str1 是通过 new 创建的
System.out.println(str1.intern() == str2); // true,因为 intern() 会返回常量池中的引用

3. HashMap 或其他集合

虽然 HashMap 本身不是缓存,但可以通过它实现简单的缓存逻辑。HashMap 提供了快速的键值对存储和检索功能,适合用作本地缓存。

import java.util.HashMap;

public class SimpleCache {
    private final HashMap<String, String> cache = new HashMap<>();

    public String get(String key) {
        return cache.get(key);
    }

    public void put(String key, String value) {
        cache.put(key, value);
    }
}

4. WeakHashMap

WeakHashMap 是一种特殊的 HashMap,它的键是弱引用。当键被垃圾回收器回收时,对应的值也会被移除。这可以用于实现简单的“弱缓存”,避免内存泄漏。

import java.util.WeakHashMap;

public class WeakCache {
    private final WeakHashMap<String, String> cache = new WeakHashMap<>();

    public String get(String key) {
        return cache.get(key);
    }

    public void put(String key, String value) {
        cache.put(key, value);
    }
}

5. SoftReferenceWeakReference

SoftReferenceWeakReference 是 Java 提供的两种引用类型,可以用于实现缓存。SoftReference 在内存不足时才会被回收,而 WeakReference 在下一次垃圾回收时就会被回收。

import java.lang.ref.SoftReference;
import java.util.HashMap;

public class SoftCache {
    private final HashMap<String, SoftReference<String>> cache = new HashMap<>();

    public String get(String key) {
        SoftReference<String> ref = cache.get(key);
        return ref != null ? ref.get() : null;
    }

    public void put(String key, String value) {
        cache.put(key, new SoftReference<>(value));
    }
}

6. java.util.concurrent

Java 的 java.util.concurrent 包提供了许多线程安全的集合类,如 ConcurrentHashMap,可以用于实现高性能的本地缓存。
 

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentCache {
    private final ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();

    public String get(String key) {
        return cache.get(key);
    }

    public void put(String key, String value) {
        cache.put(key, value);
    }
}

7. 设计模式:单例模式

单例模式可以看作是一种简单的缓存机制,用于确保某个类的实例在应用程序中只创建一次。单例模式常用于管理共享资源,如配置文件、数据库连接池等。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

8. Java 缓存库

虽然 Java 本身没有内置的缓存库,但有许多第三方库可以实现更复杂的缓存功能,如:

  • Caffeine:高性能的本地缓存库。
  • EhCache:功能丰富的本地缓存库。
  • Guava Cache:Google 提供的本地缓存库。

总结下来:

Java 本身没有内置的通用缓存机制,但它提供了许多工具和特性,可以用来实现缓存功能。

  • 常量池:用于存储字符串常量。
  • HashMapConcurrentHashMap:用于实现简单的本地缓存。
  • SoftReferenceWeakReference:用于实现弱缓存。
  • 设计模式(如单例模式):用于管理共享资源。

近日总结:完蛋了,昨天上午面的二面到现在还没有通知结果.................................................


http://www.kler.cn/a/580084.html

相关文章:

  • 学习笔记12——并发编程之线程之间协作方式
  • 『VUE』QL面试真题2025.02(详细图文注释)
  • Vue笔记
  • C++11新特性 13.共享智能指针shared_ptr
  • 基于全局拓扑图和双尺度图Transformer的视觉语言导航
  • 基于SSM+Vue的汽车维修保养预约系统+LW示例
  • RuleOS:区块链开发的“破局者”,开启Web3新纪元
  • 狮子座大数据分析(python爬虫版)
  • 【AI论文】SurveyX: 通过大型语言模型实现学术调查自动化
  • FPGA前端设计适合哪些人学?该怎么学?
  • 【kubernetes】service
  • VS 2022 安装速成指南
  • SVN 标签
  • IDEA与Maven使用-学习记录(持续补充...)
  • 全面解析Tomcat:简介、安装与配置指南
  • Git 钩子自动化部署完全指南:掌握 post-receive 触发机制与生产实践
  • 简单以太网配置
  • WPF给ListBox中的每一项添加右键菜单功能
  • Windows平台使用NDK交叉编译OpenCV
  • 在window终端创建docker容器的问题