Linux伺服器使用Redis作為資料快取,並用log4j2進行日誌記錄

HuskySir發表於2023-09-20

前言

個人網站使用Vue作為前端,SpringBoot作為後端,MySQL作為資料庫,但前端每次請求都會從MySQL資料庫中讀取資料,而MySQL資料庫的資料是儲存於伺服器磁碟中,所以響應速度有一定影響。之前瞭解過一點Redis資料庫,該資料庫資料儲存於記憶體中(也可以持久化於磁碟中),資料讀取速度就會比儲存於磁碟中的MySQL快很多,故想把Redis資料庫應用於該網站專案中。

一、安裝Redis

Linux系統安裝Redis比較簡單,可以直接透過命令列安裝,安裝過程比較簡單,在此就不贅述,下列出一些常用命令

# 更新apt
sudo apt update
# 安裝Redis
sudo apt-get install redis-server
# 設定密碼(在配置檔案redis.conf中,位置在 /etc/redis/redis.conf)
requirepass ******

# 啟動Redis服務
service redis-server start
# 停止Redis服務
service redis-server stop
# 重啟Redis服務
service redis-server restart

# 啟動Redis客戶端
redis-cli
# 測試Redis是否連線
127.0.0.1:6379> ping

注意:需要修改Redis配置檔案中的保護模式“protected-mode"為修改為no,否則會出現無法連線的情況

# 修改保護模式為no
# protected-mode yes
protected-mode no

# 若不修改可能無法連線Redis,出現以下錯誤
org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1689)
        at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1597)
······
······
······
Caused by: io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
        at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:78)
        at io.lettuce.core.RedisConnectionException.create(RedisConnectionException.java:56)
······
······
······
Caused by: java.lang.IllegalStateException: RedisHandshakeHandler not registered
        at io.lettuce.core.AbstractRedisClient.lambda$initializeChannelAsync0$6(AbstractRedisClient.java:431)
        at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590)
······
······
······

二、SpringBoot專案整合Redis

1、pom.xml新增依賴

<!-- Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、Redis資料庫連線配置 application.yml

# Redis
redis:
# 伺服器地址
host: 127.0.0.1
# 伺服器埠號
port: 6379
# 使用的資料庫索引
database: 0
# 連線超時時間
timeout: 10000
# 設定密碼
password: ******
lettuce:
  # 連線池
  pool:
    # 最大阻塞等待時間,負數表示沒有限制
    max-wait: -1
    # 連線池中最大空閒
    max-idle: 5
    # 連線池中最小空閒
    min-idle: 0
    # 連線池最大連線數
    max-active: 20

3、Redis配置類RedisConfig

package cn.huskysir.Config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableCaching //開啟註解
public class RedisConfig extends CachingConfigurerSupport {

    /**
     * retemplate相關配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 配置連線工廠
        template.setConnectionFactory(factory);

        //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(預設使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修飾符範圍,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化輸入的型別,類必須是非final修飾的,final修飾的類,比如String,Integer等會跑出異常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jacksonSeial.setObjectMapper(om);

        // 值採用json序列化
        template.setValueSerializer(jacksonSeial);
        //使用StringRedisSerializer來序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());

        // 設定hash key 和value序列化模式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();

        return template;
    }

    /**
     * 對hash型別的資料操作
     */
    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    /**
     * 對redis字串型別資料操作
     */
    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    /**
     * 對連結串列型別的資料操作
     */
    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    /**
     * 對無序集合型別的資料操作
     */
    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    /**
     * 對有序集合型別的資料操作
     */
    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }
}

4、Redis工具類RedisUtil

package cn.huskysir.Utils;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 指定快取失效時間
     *
     * @param key  鍵
     * @param time 時間(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據key 獲取過期時間
     *
     * @param key 鍵 不能為null
     * @return 時間(秒) 返回0代表為永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判斷key是否存在
     *
     * @param key 鍵
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刪除快取
     *
     * @param key 可以傳一個值 或多個
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }

    //============================String=============================

    /**
     * 普通快取獲取
     *
     * @param key 鍵
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通快取放入
     *
     * @param key   鍵
     * @param value 值
     * @return true成功 false失敗
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通快取放入並設定時間
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒) time要大於0 如果time小於等於0 將設定無限期
     * @return true成功 false 失敗
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 遞增
     *
     * @param key   鍵
     * @param delta 要增加幾(大於0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞增因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 遞減
     *
     * @param key   鍵
     * @param delta 要減少幾(小於0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞減因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    //================================Map=================================

    /**
     * HashGet
     *
     * @param key  鍵 不能為null
     * @param item 項 不能為null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 獲取hashKey對應的所有鍵值
     *
     * @param key 鍵
     * @return 對應的多個鍵值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 鍵
     * @param map 對應多個鍵值
     * @return true 成功 false 失敗
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 並設定時間
     *
     * @param key  鍵
     * @param map  對應多個鍵值
     * @param time 時間(秒)
     * @return true成功 false失敗
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一張hash表中放入資料,如果不存在將建立
     *
     * @param key   鍵
     * @param item  項
     * @param value 值
     * @return true 成功 false失敗
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一張hash表中放入資料,如果不存在將建立
     *
     * @param key   鍵
     * @param item  項
     * @param value 值
     * @param time  時間(秒)  注意:如果已存在的hash表有時間,這裡將會替換原有的時間
     * @return true 成功 false失敗
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 刪除hash表中的值
     *
     * @param key  鍵 不能為null
     * @param item 項 可以使多個 不能為null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判斷hash表中是否有該項的值
     *
     * @param key  鍵 不能為null
     * @param item 項 不能為null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash遞增 如果不存在,就會建立一個 並把新增後的值返回
     *
     * @param key  鍵
     * @param item 項
     * @param by   要增加幾(大於0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash遞減
     *
     * @param key  鍵
     * @param item 項
     * @param by   要減少記(小於0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    //============================set=============================

    /**
     * 根據key獲取Set中的所有值
     *
     * @param key 鍵
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根據value從一個set中查詢,是否存在
     *
     * @param key   鍵
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將資料放入set快取
     *
     * @param key    鍵
     * @param values 值 可以是多個
     * @return 成功個數
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 將set資料放入快取
     *
     * @param key    鍵
     * @param time   時間(秒)
     * @param values 值 可以是多個
     * @return 成功個數
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 獲取set快取的長度
     *
     * @param key 鍵
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值為value的
     *
     * @param key    鍵
     * @param values 值 可以是多個
     * @return 移除的個數
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    //===============================list=================================

    /**
     * 獲取list快取的內容
     *
     * @param key   鍵
     * @param start 開始
     * @param end   結束  0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 獲取list快取的長度
     *
     * @param key 鍵
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 透過索引 獲取list中的值
     *
     * @param key   鍵
     * @param index 索引  index>=0時, 0 表頭,1 第二個元素,依次類推;index<0時,-1,表尾,-2倒數第二個元素,依次類推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 將list放入快取
     *
     * @param key   鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入快取
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入快取
     *
     * @param key   鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入快取
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據索引修改list中的某條資料
     *
     * @param key   鍵
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N個值為value
     *
     * @param key   鍵
     * @param count 移除多少個
     * @param value 值
     * @return 移除的個數
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

三、SpringBoot專案整合log4j2

SpringBoot專案在執行的時候可能會產生一些執行資訊,如果能將這些資訊記錄下來,那麼對於該專案的執行狀態以及錯誤排查會起到一個非常好的幫助,所以採用log4j2進行日誌記錄

1、pom.xml新增依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- 排除自帶的logback依賴 -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- log4j2 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

2、log4j2.xml配置檔案,放置於resources資料夾下

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="fatal">
    <Properties>
        <Property name="baseDir" value="/home/leilee/Projects/back/logs"/>
    </Properties>

    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <!--控制檯只輸出level及以上級別的資訊(onMatch),其他的直接拒絕(onMismatch) -->
            <ThresholdFilter level="info" onMatch="ACCEPT"
                             onMismatch="DENY"/>
            <PatternLayout
                    pattern="[%d{MM:dd HH:mm:ss.SSS}] [%level] [%logger{36}] - %msg%n"/>
        </Console>

        <!--debug級別日誌檔案輸出-->
        <RollingFile name="debug_appender" fileName="${baseDir}/debug.log"
                     filePattern="${baseDir}/debug_%i.log.%d{yyyy-MM-dd}">
            <!-- 過濾器 -->
            <Filters>
                <!-- 限制日誌級別在debug及以上在info以下 -->
                <ThresholdFilter level="debug"/>
                <ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日誌格式 -->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天轉存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 檔案大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <!-- info級別日誌檔案輸出 -->
        <RollingFile name="info_appender" fileName="${baseDir}/info.log"
                     filePattern="${baseDir}/info_%i.log.%d{yyyy-MM-dd}">
            <!-- 過濾器 -->
            <Filters>
                <!-- 限制日誌級別在info及以上在error以下 -->
                <ThresholdFilter level="info"/>
                <ThresholdFilter level="error" onMatch="DENY" onMismatch="NEUTRAL"/>
            </Filters>
            <!-- 日誌格式 -->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <!-- 策略 -->
            <Policies>
                <!-- 每隔一天轉存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 檔案大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>

        <!-- error級別日誌檔案輸出 -->
        <RollingFile name="error_appender" fileName="${baseDir}/error.log"
                     filePattern="${baseDir}/error_%i.log.%d{yyyy-MM-dd}">
            <!-- 過濾器 -->
            <Filters>
                <!-- 限制日誌級別在error及以上 -->
                <ThresholdFilter level="error"/>
            </Filters>
            <!-- 日誌格式 -->
            <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
            <Policies>
                <!-- 每隔一天轉存 -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 檔案大小 -->
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="debug_appender"/>
            <AppenderRef ref="info_appender"/>
            <AppenderRef ref="error_appender"/>
        </Root>
    </Loggers>
</Configuration>

注意:第四行中value的值即輸出的log檔案的存放路徑

3、自定義log資訊

如果自己想存入一些自定義的資訊,那麼採用@Log4j2對類進行註解,然後在類中使用log的方法即可,以該網站的資料庫讀取過程為例

package cn.huskysir.Service.Impl;

import cn.huskysir.Dao.DynastyMapper;
import cn.huskysir.Dao.EmperorMapper;
import cn.huskysir.Entity.MySQL.Dynasty;
import cn.huskysir.Entity.MySQL.Emperor;
import cn.huskysir.Service.EmperorService;
import cn.huskysir.Utils.RedisUtil;
import cn.huskysir.Vo.EmperorVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * Emperor Service層(實現類)
 */
@Log4j2
@Service
public class EmperorServiceImpl implements EmperorService {

    @Resource
    EmperorMapper emperorMapper;
    @Resource
    DynastyMapper dynastyMapper;
    @Resource
    RedisUtil redisUtil;

    /**
     * 獲得所有EmperorVo物件列表
     *
     * @return
     */
    @Override
    public List<EmperorVo> getAllEmperorVoList() {
        // 判斷Redis是否存在該結果
        String key = "getAllEmperorVoList";
        if (redisUtil.hasKey(key)) {
            List<EmperorVo> emperorVoList = (List<EmperorVo>) redisUtil.get(key);
            System.out.println("由Redis得到" + key + "結果");
            // 日誌記錄
            log.info(new Date() + " 由Redis得到" + key + "資料");
            return emperorVoList;
        }

        List<Emperor> emperorList = emperorMapper.selectList(null);
        List<EmperorVo> emperorVoList = new LinkedList<>();
        for (Emperor emperor : emperorList) {
            EmperorVo emperorVo = new EmperorVo();
            BeanUtils.copyProperties(emperor, emperorVo);
            Dynasty dynasty = dynastyMapper.selectById(emperor.getDynastyId());
            emperorVo.setDynastyName(dynasty.getName());
            emperorVo.calculateTime();
            emperorVoList.add(emperorVo);
        }
        System.out.println("由MySQL得到" + key + "結果");
        // 日誌記錄
        log.info(new Date() + " 由MySQL得到" + key + "資料");
        if (redisUtil.set(key, emperorVoList, 600)) {
            System.out.println("Redis已存入" + key + "資料");
            // 日誌記錄
            log.info(new Date() + " Redis已存入" + key + "資料");
        }

        return emperorVoList;
    }

    /**
     * 根據id獲得EmperorVo物件
     *
     * @param id
     * @return
     */
    @Override
    public EmperorVo getEmperorVoById(Integer id) {
        // 判斷Redis是否存在該結果
        String key = "getEmperorVoById_" + String.valueOf(id);
        if (redisUtil.hasKey(key)) {
            EmperorVo emperorVo = (EmperorVo) redisUtil.get(key);
            System.out.println("由Redis得到" + key + "結果");
            // 日誌記錄
            log.info(new Date() + " 由Redis得到" + key + "資料");
            return emperorVo;
        }

        Emperor emperor = emperorMapper.selectById(id);
        EmperorVo emperorVo = new EmperorVo();
        BeanUtils.copyProperties(emperor, emperorVo);
        Dynasty dynasty = dynastyMapper.selectById(emperor.getDynastyId());
        emperorVo.setDynastyName(dynasty.getName());
        emperorVo.calculateTime();
        System.out.println("由MySQL得到" + key + "結果");
        // 日誌記錄
        log.info(new Date() + " 由MySQL得到" + key + "資料");
        if (redisUtil.set(key, emperorVo, 600)) {
            System.out.println("Redis已存入" + key + "資料");
            // 日誌記錄
            log.info(new Date() + " Redis已存入" + key + "資料");
        }

        return emperorVo;
    }

    /**
     * 根據dynastyId獲得所有EmperorVo物件列表
     *
     * @param dynastyId
     * @return
     */
    @Override
    public List<EmperorVo> getEmperorListByDynastyId(Integer dynastyId) {
        // 判斷Redis是否存在該結果
        String key = "getEmperorListByDynastyId_" + String.valueOf(dynastyId);
        if (redisUtil.hasKey(key)) {
            List<EmperorVo> emperorVoList = (List<EmperorVo>) redisUtil.get(key);
            System.out.println("由Redis得到" + key + "結果");
            // 日誌記錄
            log.info(new Date() + " 由Redis得到" + key + "資料");
            return emperorVoList;
        }

        QueryWrapper<Emperor> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("dynasty_id", dynastyId);
        List<Emperor> emperorList = emperorMapper.selectList(queryWrapper);
        List<EmperorVo> emperorVoList = new LinkedList<>();
        String nastyName = dynastyMapper.selectById(dynastyId).getName();
        for (Emperor emperor : emperorList) {
            EmperorVo emperorVo = new EmperorVo();
            BeanUtils.copyProperties(emperor, emperorVo);
            emperorVo.setDynastyName(nastyName);
            emperorVo.calculateTime();
            emperorVoList.add(emperorVo);
        }
        System.out.println("由MySQL得到" + key + "結果");
        // 日誌記錄
        log.info(new Date() + " 由MySQL得到" + key + "資料");
        if (redisUtil.set(key, emperorVoList, 600)) {
            System.out.println("Redis已存入" + key + "資料");
            // 日誌記錄
            log.info(new Date() + " Redis已存入" + key + "資料");
        }

        return emperorVoList;
    }
}

以“getEmperorListByDynastyId(Integer dynastyId)”方法為例,該方法是根據dynastyId獲得List物件,首先會根據方法名及dynastyIdRedis資料庫中查詢,若存在則直接返回,否則從MySQL資料庫中讀取,並將結果存入Redis資料庫中然後返回。使用log.info()記錄資料庫讀取過程,該記錄會儲存於info.log檔案中

該網站後臺的info.log日誌記錄如下

[00:54:31:770] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:141) - Wed Sep 20 00:54:31 CST 2023 由MySQL得到getEmperorListByDynastyId_1資料
[00:54:31:773] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:145) - Wed Sep 20 00:54:31 CST 2023 Redis已存入getEmperorListByDynastyId_1資料
[00:54:35:853] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:141) - Wed Sep 20 00:54:35 CST 2023 由MySQL得到getEmperorListByDynastyId_2資料
[00:54:35:863] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:145) - Wed Sep 20 00:54:35 CST 2023 Redis已存入getEmperorListByDynastyId_2資料
[00:54:37:363] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:123) - Wed Sep 20 00:54:37 CST 2023 由Redis得到getEmperorListByDynastyId_1資料
[00:54:38:043] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:123) - Wed Sep 20 00:54:38 CST 2023 由Redis得到getEmperorListByDynastyId_2資料
[00:54:39:214] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:123) - Wed Sep 20 00:54:39 CST 2023 由Redis得到getEmperorListByDynastyId_1資料
[00:54:39:936] [INFO] - cn.huskysir.Service.Impl.EmperorServiceImpl.getEmperorListByDynastyId(EmperorServiceImpl.java:123) - Wed Sep 20 00:54:39 CST 2023 由Redis得到getEmperorListByDynastyId_2資料

四、總結

關於SpringBoot專案配置Redis與log4j2是查詢官方檔案以及他人部落格得到的,本文中的Redis配置類、Redis工具類以及log4j2.xml配置檔案來自網路,查證源自何處比較麻煩,所以在此感謝所有人的分享!

相關文章