zoukankan      html  css  js  c++  java
  • 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客户端

     

     这里有个问题可以思考:传统的redis集群,即cluster,也有主从模式,现在为什么大家都选择sentinel主从模式?

     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.配置application.yml

     1 spring:
     2   redis:
    # 哨兵模式推荐使用lettuce作为客户端,弃用jedis
    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时,就会走缓存

  • 相关阅读:
    Exception in thread "main" java.io.IOException: Cannot run program "XX": CreateProcess error
    用eclipse打包mapreduce程序 运行出现解析路径错误的诡异问题
    HTMLParser学习笔记(一)
    Prim算法实现
    hadoop mapreduce 出现找不到 各种类的错误
    搜索引擎的基本原理
    ArrayList 和数组 在mapreduce编程中序列化
    读《做你自己》
    对于通过视频学习编程的建议
    长篇文档排版技巧
  • 原文地址:https://www.cnblogs.com/dz-boss/p/12190065.html
Copyright © 2011-2022 走看看