mybatisplus自定义redis缓存管理器

时间: 2023-05-26 16:04:23 浏览: 32
MyBatis Plus提供了默认的Redis缓存管理器,但是有时候我们需要根据自己的业务需求来定制一个适合自己的缓存管理器,这里简单介绍一下如何自定义Redis缓存管理器: 1. 实现Cache接口 首先需要实现MyBatis的Cache接口,该接口定义了缓存操作的基本接口方法。可以参考默认的RedisCache实现。 ``` public interface Cache { String getId(); void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key); void clear(); int getSize(); default void putObject(Object key, Object value, long ttl) { throw new UnsupportedOperationException("not support"); } } ``` 2. 实现CacheManager接口 接着需要实现MyBatis的CacheManager接口,该接口负责管理各个缓存实例的生命周期以及提供创建缓存的方法。可以参考默认的RedisCacheManager实现。 ``` public interface CacheManager { Cache getCache(String var1); void addCache(String var1); Set<String> getCacheNames(); default void destroy() { } } ``` 3. 配置缓存管理器 在MyBatis的配置文件中配置自定义的缓存管理器和缓存实现类。可以像下面这样配置: ``` <cache type="com.example.MyCacheManager"> <!-- 缓存过期时间,单位:秒,默认为永不过期 --> <property name="ttl" value="3600"></property> <!-- RedisHost --> <property name="host" value="localhost"></property> <!-- RedisPort --> <property name="port" value="6379"></property> <!-- RedisPassword --> <property name="password" value=""></property> <!-- RedisDatabase --> <property name="database" value="0"></property> <!-- RedisTimeout --> <property name="timeout" value="5000"></property> </cache> ``` 其中type属性值为自定义的CacheManager实现类。 4. 使用缓存 在Mapper接口方法上使用@CacheNamespace注解开启缓存功能并指定缓存管理器,例如: ``` @Mapper @CacheNamespace(implementation = MyCacheManager.class) public interface UserMapper { @Select("select * from user where id = #{id}") @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE) User selectById(@Param("id") int id); } ``` 这样就可以在查询User对象时自动使用自定义的Redis缓存管理器进行缓存。

相关推荐

MyBatis-Plus自带的Redis二级缓存默认使用了Jedis作为连接池,实现了比较简单的缓存管理,但是如果我们有自己定制的缓存管理器需求,可以通过继承RedisCache类并重写其中的方法来实现自定义的二级缓存管理器。 具体步骤如下: 1.继承RedisCache类并实现自己的缓存管理逻辑,例如: java public class MyRedisCache extends RedisCache { public MyRedisCache(String id) { super(id); } @Override public Object getObject(Object key) { // 自定义缓存读取逻辑 } @Override public void putObject(Object key, Object value) { // 自定义缓存写入逻辑 } @Override public Object removeObject(Object key) { // 自定义缓存删除逻辑 } //... 可以根据需要重写其他方法 } 2.覆盖MyBatis-Plus自带的Redis二级缓存配置,将自定义的缓存管理器作为二级缓存实现,例如: java @Configuration public class MybatisPlusConfig { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public RedisCacheManager redisCacheManager() { // 实现对指定缓存的自定义缓存管理器 RedisCacheWriter writer = RedisCacheWriter .nonLockingRedisCacheWriter(redisConnectionFactory); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) .entryTtl(Duration.ofMinutes(10)); Map<String, RedisCacheConfiguration> caches = new HashMap<>(); caches.put("user", config); RedisCacheManager cacheManager = new RedisCacheManager(writer, config, caches); cacheManager.setTransactionAware(false); RedisCachePrefix cachePrefix = name -> "user:" + name + ":"; cacheManager.setCachePrefix(cachePrefix); // 设置自定义的缓存管理器 cacheManager.setCaches(Collections.singletonMap("user", new MyRedisCache("user"))); return cacheManager; } } 通过上述配置可以发现,我们首先实现了一个自定义缓存管理器MyRedisCache,然后在RedisCacheManager中覆盖掉MyBatis-Plus自带的Redis二级缓存,将自定义的缓存管理器作为二级缓存实现。 最后在Mapper接口中启用二级缓存即可,例如: java @CacheNamespace(implementation = MybatisRedisCache.class, eviction = MybatisRedisCache.class) public interface UserMapper extends BaseMapper<User> { //... } 需要注意的是,在覆盖MyBatis-Plus自带的Redis二级缓存时,要确保缓存名称和之前在MyBatis配置文件中定义的缓存名称一致,否则设置无效。
MyBatis-Plus 支持内置的 Redis 作为二级缓存,但是可能会遇到一些不可避免的性能问题,例如大量查询时的 Redis 连接池瓶颈,Redis key 命名空间冲突等。 因此,我们可以采用自定义 Redis 缓存管理器来替代默认的 RedisCacheManager,自定义缓存管理器需要实现 org.apache.ibatis.cache.Cache 接口。 以下是自定义 Redis 缓存管理器的示例代码: java public class CustomRedisCache implements Cache { private final String id; // 缓存实例名称 private final RedisTemplate<String, Object> redisTemplate; // RedisTemplate 实例 private static final long EXPIRE_TIME_IN_SECONDS = 3600; // 缓存过期时间,单位:秒 public CustomRedisCache(String id, RedisTemplate<String, Object> redisTemplate) { if (id == null || redisTemplate == null) { throw new IllegalArgumentException("缓存实例名称和 RedisTemplate 实例均不能为空!"); } this.id = id; this.redisTemplate = redisTemplate; } @Override public String getId() { return this.id; } @Override public void putObject(Object key, Object value) { if (key == null) { return; } redisTemplate.opsForValue().set(key.toString(), value, EXPIRE_TIME_IN_SECONDS, TimeUnit.SECONDS); } @Override public Object getObject(Object key) { return key == null ? null : redisTemplate.opsForValue().get(key.toString()); } @Override public Object removeObject(Object key) { if (key == null) { return null; } redisTemplate.delete(key.toString()); return null; } @Override public void clear() { Set<String> keys = redisTemplate.keys("*" + getId() + "*"); if (keys != null && keys.size() > 0) { redisTemplate.delete(keys); } } @Override public int getSize() { return redisTemplate.keys("*" + getId() + "*").size(); } @Override public ReadWriteLock getReadWriteLock() { return null; } } 接下来,我们需要将自定义 Redis 缓存管理器注册到 MyBatis 中,示例代码如下: java @Configuration public class MybatisConfig { @Autowired private RedisTemplate<String, Object> redisTemplate; @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(dataSource); sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml")); sqlSessionFactory.setPlugins(new Interceptor[]{new PaginationInterceptor()}); sqlSessionFactory.setCache(new CustomRedisCache("mybatis_cache", redisTemplate)); // 注册自定义缓存管理器 return sqlSessionFactory; } } 最后,我们还需要在 MyBatis-Plus 的配置文件 mybatis-plus.yml 中添加一条配置,将 MyBatis 的缓存管理器设置为自定义的缓存管理器: yml mybatis-plus: configuration: cache-enabled: true # 允许缓存 # 使用自定义 Redis 缓存管理器 local-cache: # 是否使用一级缓存,默认为 true enabled: true # 默认缓存过期时间,单位:毫秒,默认值为 -1,即永不过期 ttl: -1 # 一级缓存最大数量,默认值为 1024 size: 1024 second-cache: # 是否使用二级缓存,默认为 true enabled: true # 默认缓存过期时间,单位:毫秒,默认值为 -1,即永不过期 ttl: -1 # 内置二级缓存管理器,支持Redis、Ehcache、Caffeine、H2、LevelDB、J2Cache等 cache-manager: com.baomidou.mybatisplus.extension.caches.RedisCacheManager # 自定义二级缓存管理器,必须实现 org.apache.ibatis.cache.Cache 接口 custom-cache: com.example.CustomRedisCache 参考链接: - https://mp.weixin.qq.com/s/GvF8ffYQbeytE0glCNV9Xg
MybatisPlus提供了自定义Redis缓存的功能,可以通过自定义Redis缓存实现数据的快速查询。 1. 引入Redis依赖 xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2. 自定义缓存 java @Component public class RedisCache implements Cache { private final RedisTemplate<Object, Object> redisTemplate; private final String cacheName; private final long ttl; public RedisCache(RedisTemplate<Object, Object> redisTemplate, String cacheName) { this.redisTemplate = redisTemplate; this.cacheName = cacheName; this.ttl = 60 * 5; //默认5分钟过期时间 } public RedisCache(RedisTemplate<Object, Object> redisTemplate, String cacheName, long ttl) { this.redisTemplate = redisTemplate; this.cacheName = cacheName; this.ttl = ttl; } @Override public String getId() { return cacheName; } @Override public void putObject(Object key, Object value) { redisTemplate.opsForValue().set(key, value, ttl, TimeUnit.SECONDS); } @Override public Object getObject(Object key) { return redisTemplate.opsForValue().get(key); } @Override public Object removeObject(Object key) { redisTemplate.delete(key); return null; } @Override public void clear() { redisTemplate.delete(redisTemplate.keys("*" + cacheName + "*")); } @Override public int getSize() { return Math.toIntExact(redisTemplate.keys("*" + cacheName + "*").size()); } @Override public ReadWriteLock getReadWriteLock() { return null; } } 3. 注册自定义缓存 java @Configuration @EnableCaching public class CacheConfig extends CachingConfigurerSupport { private final RedisConnectionFactory redisConnectionFactory; public CacheConfig(RedisConnectionFactory redisConnectionFactory) { this.redisConnectionFactory = redisConnectionFactory; } @Bean public CacheManager cacheManager() { RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10)) .disableCachingNullValues(); RedisCacheConfiguration userCacheConfig = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(5)) .disableCachingNullValues() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<String, RedisCacheConfiguration>() {{ put("user", userCacheConfig); }}; RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(defaultCacheConfig) .withInitialCacheConfigurations(cacheConfigurations) .build(); return cacheManager; } @Bean @Override public CacheResolver cacheResolver() { return new SimpleCacheResolver(cacheManager()); } @Bean @Override public CacheErrorHandler errorHandler() { return new SimpleCacheErrorHandler(); } @Bean public Cache redisCache(RedisTemplate<Object, Object> redisTemplate) { return new RedisCache(redisTemplate, "product"); } } 4. 使用自定义缓存 在Mapper接口方法上添加@Cacheable注解,指定使用自定义的Redis缓存即可。 java @Mapper public interface UserMapper extends BaseMapper<User> { @Cacheable(value = "user", key = "#id") User getById(Long id); }
MybatisPlus已经提供了redis二级缓存的实现,只需要在配置文件中开启对应选项即可。如果需要自定义redis二级缓存的实现,可以通过实现Cache接口来实现。 1. 定义缓存类 java public class RedisCache implements Cache { private RedisTemplate<Object, Object> redisTemplate; private String cacheName; private final String CACHE_PREFIX = "mybatis_cache:"; public RedisCache(String cacheName) { this.cacheName = cacheName; } @Override public String getId() { return CACHE_PREFIX + cacheName; } @Override public void putObject(Object key, Object value) { redisTemplate.opsForHash().put(getId(), key, value); } @Override public Object getObject(Object key) { return redisTemplate.opsForHash().get(getId(), key); } @Override public Object removeObject(Object key) { return redisTemplate.opsForHash().delete(getId(), key); } @Override public void clear() { redisTemplate.delete(getId()); } @Override public int getSize() { return Math.toIntExact(redisTemplate.opsForHash().size(getId())); } @Override public ReadWriteLock getReadWriteLock() { return null; } public void setRedisTemplate(RedisTemplate<Object, Object> redisTemplate) { this.redisTemplate = redisTemplate; } } 2. 配置RedisTemplate java @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setDefaultSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); redisTemplate.afterPropertiesSet(); return redisTemplate; } 3. 配置RedisCacheManager java @Bean public RedisCacheManager redisCacheManager(RedisTemplate<Object, Object> redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(new RedisCacheWriter() { @Override public void put(String name, byte[] key, byte[] value, Duration ttl) { redisTemplate.opsForHash().put(name, key, value); } @Override public byte[] get(String name, byte[] key) { return redisTemplate.opsForHash().get(name, key); } @Override public byte[] putIfAbsent(String name, byte[] key, byte[] value, Duration ttl) { byte[] currentValue = get(name, key); if (currentValue == null) { put(name, key, value, ttl); return null; } else { return currentValue; } } @Override public void remove(String name, byte[] key) { redisTemplate.opsForHash().delete(name, key); } @Override public void clean(String name, byte[] pattern) { Set<Object> keys = redisTemplate.opsForHash().keys(name); if (!CollectionUtils.isEmpty(keys)) { for (Object key : keys) { byte[] keyBytes = (byte[]) key; if (WildcardMatcher.match(new String(pattern), new String(keyBytes))) { remove(name, keyBytes); } } } } @Override public void clear(String name) { redisTemplate.delete(name); } @Override public void close() { // do nothing } },redisTemplate); return cacheManager; } 4. 配置缓存设置 java @MapperScan(value = "com.example.mapper", annotationClass = MyBatisPlusRedisCache.class) @Configuration public class RedisCacheConfig extends MybatisPlusPropertiesCustomizer { private final RedisTemplate<Object, Object> redisTemplate; private final RedisCacheManager redisCacheManager; public RedisCacheConfig(RedisTemplate<Object, Object> redisTemplate, RedisCacheManager redisCacheManager) { super(); this.redisTemplate = redisTemplate; this.redisCacheManager = redisCacheManager; } @Override public void customize(MybatisPlusProperties properties) { // 开启redis缓存 properties.getGlobalConfig().setCacheEnabled(true); properties.getGlobalConfig().setDefaultCache(new RedisCache(MpRedisCacheEnum.SECOND_CACHE_MODE.getCacheName())); // 自定义redis缓存 Map<String, Cache> cacheMap = new HashMap<>(); cacheMap.put(MpRedisCacheEnum.SECOND_CACHE_MODE.getCacheName(), new RedisCache(MpRedisCacheEnum.SECOND_CACHE_MODE.getCacheName())); redisCacheManager.setCaches(cacheMap); MybatisConfiguration configuration = properties.getConfiguration(); configuration.addInterceptor(new MybatisPlusRedisCacheInterceptor()); } } 5. 配置自定义拦截器 java public class MybatisPlusRedisCacheInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; Object parameter = invocation.getArgs()[1]; CacheKey cacheKey = mappedStatement.getCacheKey(parameter, mappedStatement.getConfiguration(), mappedStatement.getBoundSql(parameter)); BoundSql boundSql = mappedStatement.getBoundSql(parameter); Cache cache = mappedStatement.getCache(); if (cache instanceof RedisCache) { RedisCache redisCache = (RedisCache) cache; redisCache.setRedisTemplate(SpringUtil.getBean(RedisTemplate.class)); } return invocation.proceed(); } } 6. 定义注解标记需要采用自定义Redis缓存的方法 java @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyBatisPlusRedisCache { } 7. 在Mapper方法上添加注解 java @Mapper @MyBatisPlusRedisCache public interface UserMapper extends BaseMapper<User> { } 这样就完成了自定义Redis二级缓存的实现。注意,如果需要使用分布式锁来保证多线程下的缓存穿透问题,需要在putObject方法中添加分布式锁逻辑。
MyBatis-Plus 本身不支持二级缓存,但它可以与第三方缓存框架集成,比如 Redis。下面是如何使用 Redis 作为二级缓存的步骤: 1. 引入 Redis 依赖 在 pom.xml 文件中添加 Redis 相关依赖: xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-redis</artifactId> <version>2.1.1-SNAPSHOT</version> </dependency> 其中,spring-boot-starter-data-redis 是 SpringBoot 使用 Redis 的依赖,mybatis-redis 是 MyBatis-Plus 工具包支持 Redis 的依赖。 2. 配置 Redis 在 application.yml 文件中添加 Redis 配置: yaml spring: redis: host: localhost port: 6379 password: 3. 配置 Redis 缓存 在 MyBatis 的配置文件中配置 Redis 缓存: xml <cache type="org.mybatis.caches.redis.RedisCache"/> 4. 开启 Redis 二级缓存 在 MyBatis-Plus 的全局配置文件中,开启 Redis 二级缓存: java @Configuration public class MybatisPlusConfig { /** * 开启Mybatis-Plus二级缓存,需要配置RedisCache类 */ @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setCacheEnabled(true) .addCache(new RedisCache("mybatis-plus-redis-cache", true)); } } 其中,RedisCache 参数说明: - 第一个参数为缓存名称,可以自定义。 - 第二个参数为是否开启序列化,默认为 true。 至此,使用 Redis 作为二级缓存已经完成。在 MyBatis-Plus 的 CRUD 操作中,如果数据在 Redis 中存在,则直接从 Redis 中获取数据,否则从数据库中查询数据并缓存到 Redis 中。这样可以大大提高查询效率,减轻数据库负担。
以下是一个使用MyBatis Plus和Redis作为二级缓存的示例代码: 1. 配置RedisTemplate java @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); return redisTemplate; } } 2. 配置MyBatis Plus java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(RedisTemplate<String, Object> redisTemplate) { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // Redis 二级缓存插件 RedisCache redisCache = new RedisCache(redisTemplate); Properties properties = new Properties(); properties.setProperty("redisCache.expire", "3600"); properties.setProperty("redisCache.cacheNullObject", "true"); RedisCacheInterceptor redisCacheInterceptor = new RedisCacheInterceptor(redisCache, properties); interceptor.addInnerInterceptor(redisCacheInterceptor); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer(MybatisPlusInterceptor mybatisPlusInterceptor) { return configuration -> configuration.addInterceptor(mybatisPlusInterceptor); } } 3. 使用@CacheNamespace注解开启缓存 java @CacheNamespace(implementation = RedisCache.class, eviction = RedisCache.class) public interface UserMapper extends BaseMapper<User> { @Cacheable(value = "user:id", key = "#id") User getUserById(Long id); @CachePut(value = "user:id", key = "#user.id") int updateUserById(User user); @CacheEvict(value = "user:id", key = "#id") int deleteUserById(Long id); } 在这里,@CacheNamespace注解用于开启Redis缓存,并指定了缓存的实现类和清理策略。 @Cacheable注解用于查询缓存中的数据,@CachePut注解用于更新缓存中的数据,@CacheEvict注解用于删除缓存中的数据。 还可以在@Cacheable注解中指定缓存的名称和缓存的键值,以及在@CachePut和@CacheEvict注解中指定缓存的键值。 注意:在使用Redis作为二级缓存时,需要在mapper中使用@Cacheable注解进行数据的缓存和查询,同时要保证实体类的序列化和反序列化能够正确进行。
Mybatisplus自定义CustomRedisCache可以实现将查询结果缓存到Redis中,可以提高查询效率和减轻数据库的压力。下面是实现步骤: 1.自定义缓存类CustomRedisCache,并继承org.apache.ibatis.cache.decorators.RedisCache类,覆盖get、put、remove、clear等方法。 2.在CustomRedisCache中,实现对Redis缓存的相关操作,包括序列化、反序列化、过期时间的设置等。 3.在Mybatis的配置文件中,添加CustomRedisCache类的配置信息。 4.在需要使用缓存的Mapper接口中,添加@CacheNamespace注解,并指定缓存类为CustomRedisCache。 下面是CustomRedisCache的示例代码: public class CustomRedisCache extends RedisCache { private static Logger logger = LoggerFactory.getLogger(CustomRedisCache.class); private final RedisTemplate<String, Object> redisTemplate; private final String id; private final long expiration; public CustomRedisCache(String id, RedisTemplate<String, Object> redisTemplate, long expiration) { super(id); this.redisTemplate = redisTemplate; this.id = id; this.expiration = expiration; } @Override public void putObject(Object key, Object value) { try { String cacheKey = getCacheKey(key); redisTemplate.opsForValue().set(cacheKey, value, expiration, TimeUnit.SECONDS); logger.debug("Put query result to redis cache [{},{}]", id, cacheKey); } catch (Throwable t) { logger.error("Redis put failed", t); } } @Override public Object getObject(Object key) { try { String cacheKey = getCacheKey(key); Object value = redisTemplate.opsForValue().get(cacheKey); logger.debug("Get query result from redis cache [{},{}]", id, cacheKey); return value; } catch (Throwable t) { logger.error("Redis get failed, key=[{}]", key, t); return null; } } @Override public Object removeObject(Object key) { try { String cacheKey = getCacheKey(key); redisTemplate.delete(cacheKey); logger.debug("Remove cached query result from redis cache [{},{}]", id, cacheKey); } catch (Throwable t) { logger.error("Redis remove failed, key=[{}]", key, t); } return null; } @Override public void clear() { try { Set<String> keys = redisTemplate.keys("*:" + id + "*"); redisTemplate.delete(keys); logger.debug("Clear all the cached query results from redis cache [{}], size=[{}]", id, keys.size()); } catch (Throwable t) { logger.error("Redis clear failed", t); } } @Override public int getSize() { try { Long size = redisTemplate.execute(RedisConnection::dbSize); return size.intValue(); } catch (Throwable t) { logger.error("Redis get size failed", t); return 0; } } private String getCacheKey(Object key) { return prefix + ":" + key.toString(); } } 在Mybatis配置文件中,添加CustomRedisCache的配置信息: <cache type="com.example.CustomRedisCache"> </cache> 在需要使用缓存的Mapper接口中,添加@CacheNamespace注解,并指定缓存类为CustomRedisCache: @CacheNamespace(implementation = com.example.CustomRedisCache.class) public interface UserMapper { @Select("select * from user where id = #{id}") User selectById(@Param("id") Long id); }
RedisCacheManager是Spring提供的一个缓存管理器,用于将数据缓存在Redis中。如果需要自定义RedisCacheManager,可以继承它并重写相关方法。 首先,需要创建一个类,继承RedisCacheManager: public class CustomRedisCacheManager extends RedisCacheManager { public CustomRedisCacheManager(RedisOperations redisOperations) { super(redisOperations); } @Override protected RedisCache createCache(String cacheName) { // 自定义缓存实现 return new CustomRedisCache(cacheName, (isUsePrefix() ? getCachePrefix().prefix(cacheName) : null), getRedisOperations(), getExpiration()); } } 在这个类中,我们重写了createCache方法,用于创建自定义的缓存实现。我们可以创建一个CustomRedisCache类,继承RedisCache,然后在这个类中实现自己的缓存逻辑。 例如,下面是一个简单的CustomRedisCache实现: public class CustomRedisCache extends RedisCache { public CustomRedisCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations, long expiration) { super(name, prefix, redisOperations, expiration); } @Override public ValueWrapper get(Object key) { // 自定义缓存逻辑 return super.get(key); } @Override public void put(Object key, Object value) { // 自定义缓存逻辑 super.put(key, value); } @Override public void evict(Object key) { // 自定义缓存逻辑 super.evict(key); } @Override public void clear() { // 自定义缓存逻辑 super.clear(); } } 在这个CustomRedisCache类中,我们重写了RedisCache中的get、put、evict和clear方法,用于实现自己的缓存逻辑。 最后,在Spring配置文件中,使用自定义的RedisCacheManager代替默认的RedisCacheManager。例如: <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> </bean> <bean id="cacheManager" class="com.example.CustomRedisCacheManager"> <constructor-arg ref="redisTemplate"/> <value>cache1</value> <value>cache2</value> </bean> 在这个配置中,我们创建了一个CustomRedisCacheManager,并设置了缓存名称和默认过期时间。注意,这里的redisTemplate需要自己定义,并设置好相关属性。
好的,关于SpringBoot自定义Redis注解AOP的问题,我可以为您提供一些基本的介绍和示例代码。 Redis作为一种高性能的缓存和数据存储解决方案,被广泛应用于各种应用程序中。在SpringBoot应用程序中,使用Redis通常需要编写大量的重复代码,比如获取Redis连接、执行Redis命令、释放Redis连接等。这些重复代码不仅增加了开发和维护的难度,还影响了应用程序的性能。而AOP作为一种切面编程的技术,可以很好地解决这些问题。 下面是一个简单的示例代码,演示如何通过自定义注解实现对Redis操作的AOP处理: 首先,定义一个自定义注解: java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RedisCacheable { String key() default ""; long expire() default 0; } 然后,在需要被拦截的方法上添加该注解: java @Component public class RedisService { @Autowired private RedisTemplate<String, String> redisTemplate; @RedisCacheable(key = "myKey", expire = 60) public String getValue() { return redisTemplate.opsForValue().get("myKey"); } } 接下来,使用AspectJ的@Aspect注解定义一个切面类,并在该类中定义一个切点,用于匹配被@RedisCacheable注解的方法: java @Aspect @Component public class RedisAspect { @Autowired private RedisTemplate<String, String> redisTemplate; @Pointcut("@annotation(com.example.demo.annotation.RedisCacheable)") public void redisCacheablePointcut() {} @Around("redisCacheablePointcut()") public Object aroundRedisCacheable(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); RedisCacheable redisCacheable = method.getAnnotation(RedisCacheable.class); String key = redisCacheable.key(); long expire = redisCacheable.expire(); String value = redisTemplate.opsForValue().get(key); if (value != null) { return value; } Object result = joinPoint.proceed(); if (result != null) { redisTemplate.opsForValue().set(key, result.toString()); if (expire > 0) { redisTemplate.expire(key, expire, TimeUnit.SECONDS); } } return result; } } 在该切面类中,使用@Around注解定义一个环绕通知,在该通知中,首先获取被拦截方法上的@RedisCacheable注解,然后根据注解中的key值从Redis中获取数据。如果Redis中已经存在该数据,则直接返回;否则,执行被拦截方法,并将结果存储到Redis缓存中。 最后,启动SpringBoot应用程序,调用RedisService的getValue方法,就可以看到输出结果: java // 第一次调用,从数据库中获取数据,并将数据存入Redis缓存中 getValue... // 第二次调用,直接从Redis中获取数据 getValue... 以上就是一个简单的SpringBoot自定义Redis注解AOP的示例。通过使用自定义注解和AOP技术,可以更加方便地实现对Redis缓存的操作,并提高应用程序的性能。
1. 引入依赖 在 pom.xml 文件中添加以下依赖: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-extension</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.apache.ibatis</groupId> <artifactId>mybatis-redis-cache</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> 2. 配置 Redis 在 application.yml 配置文件中添加 Redis 的连接信息: spring: redis: host: 127.0.0.1 port: 6379 password: 123456 database: 0 pool: max-active: 8 max-idle: 8 min-idle: 0 max-wait: -1ms 3. 配置 MyBatis Plus 在 MyBatis Plus 配置文件中开启二级缓存并配置 Redis 缓存: mybatis-plus: configuration: cache-enabled: true # 开启二级缓存 local-cache-scope: session # 二级缓存作用域 lazy-loading-enabled: true # 开启懒加载 multiple-datasource-enabled: true # 开启多数据源 global-config: db-config: id-type: auto # 主键ID类型 field-strategy: not_empty # 字段非空验证 swagger2: true # 是否开启Swagger2 cache: enabled: true # 开启缓存 type: redis # 缓存类型 # 设置缓存前缀,默认是 mybatis:cache: # prefix: mybatisplus: spring: redis: cache: # 过期时间,默认1天 ttl: 86400 # 二级缓存前缀,默认是 mybatisplus:cache: key-prefix: mybatis-plus:cache: # 条目数量,默认256个 max-number-of-elements-in-cache: 256 4. 实体类开启缓存 在需要开启缓存的实体类上添加 @CacheNamespace 注解: @Data @NoArgsConstructor @TableName("student") @CacheNamespace(implementation = MybatisRedisCache.class, eviction = MybatisRedisCache.class, flushInterval = 60000) public class Student implements Serializable { @TableId(type = IdType.AUTO) private Long id; @TableField("name") private String name; @TableField("age") private Integer age; } 其中,implementation 和 eviction 属性的值均为 MybatisRedisCache.class,表示该实体类使用 Redis 缓存,并且缓存失效时间为 1 分钟(60 秒)。 5. 注册 Redis 缓存插件 在 Spring Boot 应用启动类中注册 Redis 缓存插件: @Configuration public class MyBatisPlusConfig { @Bean public RedisCachePlugin redisCachePlugin(RedisTemplate<Object, Object> redisTemplate) { return new RedisCachePlugin(redisTemplate); } } 6. 测试缓存 使用以下代码进行测试: @Test public void testRedisCache() { Student student1 = studentService.getById(1L); Student student2 = studentService.getById(1L); System.out.println("student1:" + student1); System.out.println("student2:" + student2); Assert.assertEquals(student1, student2); } 第一次查询会从数据库中获取数据并保存到 Redis 缓存,第二次查询会直接从 Redis 缓存中获取数据,输出结果如下: DEBUG [MybatisRedisCache] [Session XX] [Namespace com.example.demo.entity.Student] [Cache INSERT] Student(id=1, name=Tom, age=20) student1:Student(id=1, name=Tom, age=20) student2:Student(id=1, name=Tom, age=20)
布隆过滤器可以用于解决Redis缓存穿透问题。布隆过滤器是一种数据结构,它可以判断一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好,但缺点是有一定的误识别率和删除困难。\[3\] 在解决Redis缓存穿透问题时,可以使用布隆过滤器来过滤掉那些不存在于数据库中的请求,从而减轻数据库的压力。具体实现步骤如下: 1. 引入Redisson依赖,并配置RedissonClient。\[2\] 2. 创建布隆过滤器的封装类,使用RedissonClient初始化布隆过滤器,并设置预计元素数量和误差率。\[2\] 3. 在查询之前,先通过布隆过滤器判断请求的数据是否存在于布隆过滤器中。如果不存在,则直接返回结果,避免查询数据库。\[2\] 4. 如果布隆过滤器判断数据可能存在于布隆过滤器中,再去查询Redis缓存。如果缓存中存在数据,则直接返回结果。如果缓存中不存在数据,则查询数据库,并将查询结果放入缓存中。\[1\] 通过使用布隆过滤器,可以有效地减少对数据库的查询次数,提高系统的性能和响应速度,同时也可以防止缓存穿透的问题。 #### 引用[.reference_title] - *1* *2* [一文搞懂布隆过滤器以及如何解决Redis的缓存穿透问题](https://blog.csdn.net/qq_43750656/article/details/109014932)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* *4* *5* [基于布隆过滤器解决Redis缓存穿透的问题](https://blog.csdn.net/weixin_39555954/article/details/120280278)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

最新推荐

Java自定义注解实现Redis自动缓存的方法

本篇文章主要介绍了Java自定义注解实现Redis自动缓存的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。

Redis缓存穿透,缓存击穿和缓存雪崩

一、缓存处理流程 处理Reids缓存引发的问题时,我们首先得知道缓存处理的一个流程,如下图: 二、缓存穿透,缓存击穿和缓存雪崩 缓存穿透 描述:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如...

Spring Cache手动清理Redis缓存

主要介绍了Spring Cache手动清理Redis缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

java操作Redis缓存设置过期时间的方法

主要介绍了java操作Redis缓存设置过期时间的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

提高redis缓存命中率的方法

在本篇文章里小编给大家整理了关于怎么提高redis缓存命中率的相关知识点内容,有兴趣的朋友们跟着学习下。

代码随想录最新第三版-最强八股文

这份PDF就是最强⼋股⽂! 1. C++ C++基础、C++ STL、C++泛型编程、C++11新特性、《Effective STL》 2. Java Java基础、Java内存模型、Java面向对象、Java集合体系、接口、Lambda表达式、类加载机制、内部类、代理类、Java并发、JVM、Java后端编译、Spring 3. Go defer底层原理、goroutine、select实现机制 4. 算法学习 数组、链表、回溯算法、贪心算法、动态规划、二叉树、排序算法、数据结构 5. 计算机基础 操作系统、数据库、计算机网络、设计模式、Linux、计算机系统 6. 前端学习 浏览器、JavaScript、CSS、HTML、React、VUE 7. 面经分享 字节、美团Java面、百度、京东、暑期实习...... 8. 编程常识 9. 问答精华 10.总结与经验分享 ......

事件摄像机的异步事件处理方法及快速目标识别

934}{基于图的异步事件处理的快速目标识别Yijin Li,Han Zhou,Bangbang Yang,Ye Zhang,Zhaopeng Cui,Hujun Bao,GuofengZhang*浙江大学CAD CG国家重点实验室†摘要与传统摄像机不同,事件摄像机捕获异步事件流,其中每个事件编码像素位置、触发时间和亮度变化的极性。在本文中,我们介绍了一种新的基于图的框架事件摄像机,即SlideGCN。与最近一些使用事件组作为输入的基于图的方法不同,我们的方法可以有效地逐个事件处理数据,解锁事件数据的低延迟特性,同时仍然在内部保持图的结构。为了快速构建图,我们开发了一个半径搜索算法,该算法更好地利用了事件云的部分正则结构,而不是基于k-d树的通用方法。实验表明,我们的方法降低了计算复杂度高达100倍,相对于当前的基于图的方法,同时保持最先进的性能上的对象识别。此外,我们验证了我们的方�

下半年软件开发工作计划应该分哪几个模块

通常来说,软件开发工作可以分为以下几个模块: 1. 需求分析:确定软件的功能、特性和用户需求,以及开发的目标和约束条件。 2. 设计阶段:根据需求分析的结果,制定软件的架构、模块和接口设计,确定开发所需的技术和工具。 3. 编码实现:根据设计文档和开发计划,实现软件的各项功能和模块,编写测试用例和文档。 4. 测试阶段:对软件进行各种测试,包括单元测试、集成测试、功能测试、性能测试、安全测试等,确保软件的质量和稳定性。 5. 发布和部署:将软件打包发布,并进行部署和安装,确保用户可以方便地使用软件。 6. 维护和更新:对软件进行维护和更新,修复漏洞和Bug,添加新的特性和功能,保证

数据结构1800试题.pdf

你还在苦苦寻找数据结构的题目吗?这里刚刚上传了一份数据结构共1800道试题,轻松解决期末挂科的难题。不信?你下载看看,这里是纯题目,你下载了再来私信我答案。按数据结构教材分章节,每一章节都有选择题、或有判断题、填空题、算法设计题及应用题,题型丰富多样,共五种类型题目。本学期已过去一半,相信你数据结构叶已经学得差不多了,是时候拿题来练练手了,如果你考研,更需要这份1800道题来巩固自己的基础及攻克重点难点。现在下载,不早不晚,越往后拖,越到后面,你身边的人就越卷,甚至卷得达到你无法想象的程度。我也是曾经遇到过这样的人,学习,练题,就要趁现在,不然到时你都不知道要刷数据结构题好还是高数、工数、大英,或是算法题?学完理论要及时巩固知识内容才是王道!记住!!!下载了来要答案(v:zywcv1220)。

开集域自适应方法及其在靶点发现中的应用

9322基于开集域自适应的新靶点发现Taotao Jing< $,Hongfu LiuXiang,and Zhengming Ding<$†美国杜兰大学计算机科学系‡美国布兰代斯大学Michtom计算机科学学院网址:tjing@tulane.edu,hongfuliu@brandeis.edu,网址:www.example.com,zding1@tulane.edu摘要开集域自适应算法(OSDA)认为目标域包含了在外部源域中未观察到的新类别的样本不幸的是,现有的OSDA方法总是忽略了看不见的类别的信息的需求,并简单地将它们识别为“未知”集合而没有进一步的这促使我们通过探索底层结构和恢复其不可解释的语义属性来更具体地理解未知类别。在本文中,我们提出了一种新的框架,以准确地识别目标领域中的可见类别,并有效地恢复未见过的类别的语义属性具体而言,结构保持部分对齐开发,通过域不变的特征学习识别看到的基于视觉图的属性传播是为了通过视觉语义映射将可见属�