本片文章續《Spring Boot 入門(九):集成Quartz定時任務》。本文主要基於redis實現了mybatis二級緩存。較redis緩存,mybaits自帶緩存存在缺點(自行谷歌)。本文是基於docker安裝redis主從模式。html
(1)首先安裝redis集羣模式,創建redis目錄,並編寫主從模式docker-compose.yml文件java
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 -dredis
(3).創建sentinel文件,並編寫docker-compose.yml文件spring
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),內容是如出一轍sql
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 -ddocker
(5).驗證redis是否已經成功啓動apache
進入容器:docker exec -it redis-sentinel-1 /bin/bash緩存
鏈接redis:redis-cli -p 26379bash
以下圖,表示啓動成功mybatis
也能夠經過桌面客戶端查看是否啓動成功,如圖,我使用的RedisDesktopManager客戶端
網上一大堆,根據本身須要選擇合適的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 }
@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父接口中增長註解,這樣,全部的接口就不須要單獨增長這個註解(根據業務須要自行素選擇)。
當進行CURD操做時,相關的檢索sql語句就會緩存到redis,如圖:
當再次對相關數據進行CRUD時,就會走緩存