Spring Boot 入门(十):集成Redis哨兵模式,实现Mybatis二级缓存
本片文章续《Spring Boot 入门(九):集成Quartz定时任务》。本文主要基于redis实现了mybatis二级缓存。较redis缓存,mybaits自带缓存存在缺点(自行谷歌)。本文是基于docker安装redis主从模式。
1.redis安装
(1)首先安装redis集群模式,建立redis目录,并编写主从模式docker-compose.yml文件
- 1 version: '3.1'
- 2 services:
- 3 master:
- 4 image: redis
- 5 container_name: redis-master
- 6 ports:
- 7 - 6379:6379
- 8
- 9 slave1:
- 10 image: redis
- 11 container_name: redis-slave-1
- 12 ports:
- 13 - 6380:6379
- 14 command: redis-server --slaveof redis-master 6379
- 15
- 16 slave2:
- 17 image: redis
- 18 container_name: redis-slave-2
- 19 ports:
- 20 - 6381:6379
- 21 command: redis-server --slaveof redis-master 6379
(2).启动 docker-compose up -d
(3).建立sentinel文件,并编写docker-compose.yml文件
- 1 version: '3.1'
- 2 services:
- 3 sentinel1:
- 4 image: redis
- 5 container_name: redis-sentinel-1
- 6 ports:
- 7 - 26379:26379
- 8 command: redis-sentinel /usr/local/etc/redis/sentinel.conf
- 9 volumes:
- 10 - ./sentinel1.conf:/usr/local/etc/redis/sentinel.conf
- 11
- 12 sentinel2:
- 13 image: redis
- 14 container_name: redis-sentinel-2
- 15 ports:
- 16 - 26380:26379
- 17 command: redis-sentinel /usr/local/etc/redis/sentinel.conf
- 18 volumes:
- 19 - ./sentinel2.conf:/usr/local/etc/redis/sentinel.conf
- 20
- 21 sentinel3:
- 22 image: redis
- 23 container_name: redis-sentinel-3
- 24 ports:
- 25 - 26381:26379
- 26 command: redis-sentinel /usr/local/etc/redis/sentinel.conf
- 27 volumes:
- 28 - ./sentinel3.conf:/usr/local/etc/redis/sentinel.conf
- 29
从模式需要sentinel的conf文件,我创建了3个容器,所以这里需要3份(sentinel1.conf sentinel2.conf sentinel3.conf),内容是一模一样
- 1 port 26379
- 2 dir /tmp
- 3 sentinel monitor mymaster 217.0.0.1 6379 2
- 4 sentinel down-after-milliseconds rmaster 30000
- 5 sentinel parallel-syncs mymaster 1
- 6 sentinel failover-timeout mymaster 180000
- 7 sentinel deny-scripts-reconfig yes
(4).启动:docker-compose up -d
(5).验证redis是否已经成功启动
进入容器:docker exec -it redis-sentinel-1 /bin/bash
连接redis:redis-cli -p 26379
如下图,表示启动成功
也可以通过桌面客户端查看是否启动成功,如图,我使用的RedisDesktopManager客户端
2.编写RedisCache工具类
网上一大堆,根据自己需要选择合适的utils(有的utils中方法很全)
- 1 package com.learn.hello.system.utils;
- 2
- 3 import lombok.extern.slf4j.Slf4j;
- 4 import org.apache.ibatis.cache.Cache;
- 5 import org.springframework.data.redis.core.RedisCallback;
- 6 import org.springframework.data.redis.core.RedisTemplate;
- 7 import org.springframework.data.redis.core.ValueOperations;
- 8
- 9 import java.util.concurrent.TimeUnit;
- 10 import java.util.concurrent.locks.ReadWriteLock;
- 11 import java.util.concurrent.locks.ReentrantReadWriteLock;
- 12
- 13 /**
- 14 * @ClassName RedisCache
- 15 * @Deccription 通过redis实现mybaits的二级缓存
- 16 * @Author DZ
- 17 * @Date 2020/1/12 22:41
- 18 **/
- 19 @Slf4j
- 20 public class RedisCache implements Cache {
- 21
- 22 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
- 23 private final String id; // cache instance id
- 24 private RedisTemplate redisTemplate;
- 25
- 26 private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis过期时间
- 27
- 28 public RedisCache(String id) {
- 29 if (id == null) {
- 30 throw new IllegalArgumentException("Cache instances require an ID");
- 31 }
- 32 this.id = id;
- 33 }
- 34
- 35 @Override
- 36 public String getId() {
- 37 return id;
- 38 }
- 39
- 40 /**
- 41 * Put query result to redis
- 42 *
- 43 * @param key
- 44 * @param value
- 45 */
- 46 @Override
- 47 public void putObject(Object key, Object value) {
- 48 try {
- 49 RedisTemplate redisTemplate = getRedisTemplate();
- 50 ValueOperations opsForValue = redisTemplate.opsForValue();
- 51 opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
- 52 log.debug("Put query result to redis");
- 53 } catch (Throwable t) {
- 54 log.error("Redis put failed", t);
- 55 }
- 56 }
- 57
- 58 /**
- 59 * Get cached query result from redis
- 60 *
- 61 * @param key
- 62 * @return
- 63 */
- 64 @Override
- 65 public Object getObject(Object key) {
- 66 try {
- 67 RedisTemplate redisTemplate = getRedisTemplate();
- 68 ValueOperations opsForValue = redisTemplate.opsForValue();
- 69 log.debug("Get cached query result from redis");
- 70 return opsForValue.get(key);
- 71 } catch (Throwable t) {
- 72 log.error("Redis get failed, fail over to db", t);
- 73 return null;
- 74 }
- 75 }
- 76
- 77 /**
- 78 * Remove cached query result from redis
- 79 *
- 80 * @param key
- 81 * @return
- 82 */
- 83 @Override
- 84 @SuppressWarnings("unchecked")
- 85 public Object removeObject(Object key) {
- 86 try {
- 87 RedisTemplate redisTemplate = getRedisTemplate();
- 88 redisTemplate.delete(key);
- 89 log.debug("Remove cached query result from redis");
- 90 } catch (Throwable t) {
- 91 log.error("Redis remove failed", t);
- 92 }
- 93 return null;
- 94 }
- 95
- 96 /**
- 97 * Clears this cache instance
- 98 */
- 99 @Override
- 100 public void clear() {
- 101 RedisTemplate redisTemplate = getRedisTemplate();
- 102 redisTemplate.execute((RedisCallback) connection -> {
- 103 connection.flushDb();
- 104 return null;
- 105 });
- 106 log.debug("Clear all the cached query result from redis");
- 107 }
- 108
- 109 /**
- 110 * This method is not used
- 111 *
- 112 * @return
- 113 */
- 114 @Override
- 115 public int getSize() {
- 116 return 0;
- 117 }
- 118
- 119 @Override
- 120 public ReadWriteLock getReadWriteLock() {
- 121 return readWriteLock;
- 122 }
- 123
- 124 private RedisTemplate getRedisTemplate() {
- 125 if (redisTemplate == null) {
- 126 redisTemplate = SpringContextHolder.getBean("redisTemplate");
- 127 }
- 128 return redisTemplate;
- 129 }
- 130 }
3.在接口类增加redis缓存注解
- @CacheNamespace(implementation = RedisCache.class)
例如:
- 1 @CacheNamespace(implementation = RedisCache.class)
- 2 public interface RoleMapper extends MyMapper<Role> {
- 3 List<Role> selectByCondition(ModelMap modelMap);
- 4
- 5 Role selectById(int id);
- 6
- 7 List<Role> selectAllRole();
- 8 }
这里也可以直接在MyMapper父接口中增加注解,这样,所有的接口就不需要单独增加这个注解(根据业务需要自行素选择)。
4.效果
当进行CURD操作时,相关的检索sql语句就会缓存到redis,如图:
当再次对相关数据进行CRUD时,就会走缓存