MyBatis开启二级缓存
前言
MyBatis-Plus(简称MP)是一个基于MyBatis的增强工具,提供了更便捷的CRUD操作和其他功能。与MyBatis相比,MyBatis-Plus并没有引入自己的缓存机制,而是直接使用了MyBatis的缓存机制。
在MyBatis中,缓存分为一级缓存和二级缓存。
一级缓存:一级缓存是SqlSession级别的缓存,它默认是开启的。当查询操作执行时,查询的结果会被缓存在SqlSession的内部数据结构中。如果后续再次执行相同的查询,MyBatis会先检查一级缓存中是否存在结果,如果存在则直接返回缓存的结果,而不会再次执行SQL语句。一级缓存的生命周期与SqlSession相同,当SqlSession关闭时,一级缓存也会被清空。
二级缓存:二级缓存是Mapper级别的缓存,它可以被多个SqlSession共享。当一个查询执行完毕后,查询的结果会被缓存到二级缓存中。当后续其他SqlSession执行相同的查询时,MyBatis会先检查二级缓存中是否存在结果,如果存在则直接返回缓存的结果,而不会再次执行SQL语句。二级缓存的生命周期与应用程序的整个生命周期相同,当应用程序关闭时,二级缓存才会被清空。
Spring Boot 整合Mybatis 开启二级缓存
图片来源与CSDN 半缘修道_半缘君
在Spring Boot中整合MyBatis,可以通过以下步骤开启二级缓存:
- 配置mybatis-config.xml文件:
在mybatis-config.xml文件中,需要添加如下配置:
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/> <!-- 开启二级缓存 -->
<setting name="lazyLoadingEnabled" value="true"/> <!-- 开启延迟加载 -->
<setting name="aggressiveLazyLoading" value="false"/> <!-- 关闭积极的延迟加载 -->
</settings>
<typeAliases>
...
</typeAliases>
<mappers>
...
</mappers>
</configuration>
- 配置mapper.xml文件:
在mapper.xml文件中,需要添加如下配置:
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
...
</mapper>
- 配置application.properties文件:
在application.properties文件中,需要添加如下配置:
# 开启MyBatis二级缓存
mybatis.configuration.cache-enabled=true
- 配置接口类:
你还可以通过在mapper接口上添加@CacheNamespace注解来启用并配置二级缓存。例如:
@CacheNamespace
public interface UserMapper {
...
}
其中,MybatisRedisCache
是自定义的缓存实现类,需要继承org.mybatis.caches.redis.RedisCache
类,并重写putObject
、getObject
和removeObject
方法。
- 配置Redis:
如果使用Redis作为二级缓存的实现,需要在application.properties
文件中添加如下配置:
# Redis配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
- 配置RedisCacheConfiguration:
在Spring Boot 2.x版本中,还需要配置RedisCacheConfiguration
,以便将Redis作为二级缓存的实现。可以通过如下方式进行配置:
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(360)) // 设置缓存有效期为六分钟
.disableCachingNullValues() // 禁止缓存null对象
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // 使用Jackson2JsonRedisSerializer序列化缓存对象
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}
以上就是在Spring Boot中整合MyBatis并开启二级缓存的具体步骤。需要注意的是,在使用二级缓存时,需要考虑缓存的有效期、缓存的清理策略等问题,以免出现脏数据或OOM等问题。
何时使用二级缓存
二级缓存是指在应用程序中使用的缓存层,位于一级缓存(通常是内存)和持久化存储(如数据库)之间。它的作用是提供更高效的数据访问和响应速度,并减轻对持久化存储的压力。下面是一些适合使用二级缓存的场景:
-
数据读取频繁但很少发生变化:如果应用程序中有一些数据在读取操作非常频繁,但很少有更新操作,那么使用二级缓存可以大大提高读取性能。这样可以避免频繁地从持久化存储中读取数据,而是将数据缓存在二级缓存中,提供更快的访问速度。
-
数据访问开销较高:某些数据的获取过程可能涉及复杂的计算、网络请求或其他开销较高的操作。在这种情况下,通过将结果缓存到二级缓存中,可以避免重复执行这些开销较高的操作,提高系统的响应速度。
-
并发读取需求:当多个用户或进程同时读取相同的数据时,使用二级缓存可以减少对持久化存储的并发访问,提高系统的并发读取能力。这样可以避免多个用户同时访问数据库,减少数据库的负载。
-
数据共享需求:如果应用程序中的多个模块或服务需要共享相同的数据,使用二级缓存可以实现数据的共享和一致性。通过将数据缓存在二级缓存中,不同的模块或服务可以共享相同的数据,避免了重复查询和数据不一致的问题。
需要注意的是,使用二级缓存也可能带来一些问题,例如缓存一致性、缓存过期和内存管理等。在使用二级缓存时,需要仔细考虑缓存的更新策略、缓存失效机制以及内存消耗等因素,确保缓存数据的正确性和系统的稳定性。
如何解决二级缓存失效
解决二级缓存失效问题的方法之一是使用缓存失效策略和缓存更新机制。下面是一个示例代码,演示了如何使用Spring Cache来处理二级缓存的失效问题。
首先,需要在应用程序中配置缓存管理器和缓存注解支持。可以使用Spring的@EnableCaching
注解启用缓存功能,并配置适当的缓存管理器(如Ehcache、Redis等)。以下是一个示例的配置类:
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager() {
// 配置缓存管理器,例如使用Ehcache
EhCacheCacheManager cacheManager = new EhCacheCacheManager();
cacheManager.setCacheManager(ehCacheManager());
return cacheManager;
}
@Bean
public net.sf.ehcache.CacheManager ehCacheManager() {
// 配置Ehcache缓存管理器
// ...
}
@Override
public KeyGenerator keyGenerator() {
// 自定义缓存键生成策略
return new MyKeyGenerator();
}
}
接下来,可以在需要缓存的方法上使用Spring的缓存注解,例如@Cacheable
、@CachePut
和@CacheEvict
。这些注解可以控制缓存的读取、更新和清除操作。以下是一个示例的服务类:
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
// 从数据库中获取产品
return productRepository.findById(id);
}
@CachePut(value = "products", key = "#product.id")
public Product saveProduct(Product product) {
// 保存产品到数据库
return productRepository.save(product);
}
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
// 从数据库中删除产品
productRepository.deleteById(id);
}
}
在上述示例中,@Cacheable
注解表示对应的方法结果会被缓存起来,@CachePut
注解表示对应的方法结果会更新缓存,@CacheEvict
注解表示对应的方法会清除缓存。通过合理使用这些注解,可以控制缓存的读取、更新和清除操作,从而解决二级缓存失效的问题。
需要注意的是,缓存的失效策略和更新机制应根据具体的业务需求进行设计。例如,可以设置合适的缓存过期时间、缓存更新的触发条件,或者在数据更新时手动清除相关的缓存等。此外,还可以结合消息队列或事件机制,实现异步缓存更新,提高系统的性能和可靠性。
以上示例代码仅供参考,实际应用中需要根据具体情况进行调整和扩展。同时,需要根据具体的缓存框架和技术选型,查阅相关文档以了解更多详细信息。