The film article continued " the Spring Getting the Boot (IX): Integrated Quartz regular tasks ." This article is mainly based on redis realized mybatis L2 cache. Redis than the cache, mybaits own cache disadvantage (their own Google). This paper is based on a master-slave mode redis docker mounted.
1.redis installation
(1) First, install redis cluster model, the establishment of redis directory, and write the main mode docker-compose.yml files from
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) Start docker-compose up -d
(3) Establish sentinel file and write docker-compose.yml file
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
From the model requires sentinel of conf file, I created three vessels, so there need 3 parts (sentinel1.conf sentinel2.conf sentinel3.conf), the content is exactly the same
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) Start: docker-compose up -d
(5) Verify whether the successful launch redis
Into the container: docker exec -it redis-sentinel-1 / bin / bash
Connecting redis: redis-cli -p 26379
Are plans that start success
You can also check whether a successful start by end desktop client, as shown, RedisDesktopManager client I use end
There is a problem you can think about: traditional redis clusters, namely cluster, there are master-slave mode, now why do we choose to sentinel master-slave mode?
2. Write RedisCache Tools
Online a lot, you need to choose the right utils according to (some utils method is very wide)
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.配置application.yml
1 spring: 2 redis: 3 lettuce: 4 # 连接池配置 5 pool: 6 # 连接池中的最小空闲连接,默认 0 7 min-idle: 0 8 # 连接池中的最大空闲连接,默认 8 9 max-idle: 8 10 # 连接池最大阻塞等待时间(使用负值表示没有限制),默认 -1ms 11 max-wait: -1ms 12 # 连接池最大连接数(使用负值表示没有限制),默认 8 13 max-active: 8 14 # 集群模式 15 # cluster: 16 # nodes: 192.168.1.12:6379,192.168.1.12:6380,192.168.1.12:6381 17 # 哨兵模式 18 sentinel: 19 master: mymaster 20 nodes: 192.168.1.12:26379,192.168.1.12:26380,192.168.1.12:26381
1 mybatis: 2 mapper-locations: classpath:mapper/*.xml 3 # 此配置的作用:xml中不用写实体类的全路径 4 type-aliases-package: com.learn.hello.modules.entity 5 # 查询的null字段也返回 6 configuration: 7 call-setters-on-nulls: true 8 # 开启二级缓存 9 cache-enabled: true
5.效果
当进行CURD操作时,相关的检索sql语句就会缓存到redis,如图:
当再次对相关数据进行CRUD时,就会走缓存