Linux服務(wù)器使用Redis作為數(shù)據(jù)緩存并用log4j2進(jìn)行日志記錄的過程分享
前言
個人網(wǎng)站使用Vue作為前端,SpringBoot作為后端,MySQL作為數(shù)據(jù)庫,但前端每次請求都會從MySQL數(shù)據(jù)庫中讀取數(shù)據(jù),而MySQL數(shù)據(jù)庫的數(shù)據(jù)是存儲于服務(wù)器磁盤中,所以響應(yīng)速度有一定影響。之前了解過一點(diǎn)Redis數(shù)據(jù)庫,該數(shù)據(jù)庫數(shù)據(jù)存儲于內(nèi)存中(也可以持久化于磁盤中),數(shù)據(jù)讀取速度就會比存儲于磁盤中的MySQL快很多,故想把Redis數(shù)據(jù)庫應(yīng)用于該網(wǎng)站項(xiàng)目中。
一、安裝Redis
Linux系統(tǒng)安裝Redis比較簡單,可以直接通過命令行安裝,安裝過程比較簡單,在此就不贅述,下列出一些常用命令
# 更新apt sudo apt update # 安裝Redis sudo apt-get install redis-server # 設(shè)置密碼(在配置文件redis.conf中,位置在 /etc/redis/redis.conf) requirepass ****** # 啟動Redis服務(wù) service redis-server start # 停止Redis服務(wù) service redis-server stop # 重啟Redis服務(wù) service redis-server restart # 啟動Redis客戶端 redis-cli # 測試Redis是否連接 127.0.0.1:6379> ping
注意:需要修改Redis配置文件中的保護(hù)模式“protected-mode"為修改為no,否則會出現(xiàn)無法連接的情況
# 修改保護(hù)模式為no # protected-mode yes protected-mode no # 若不修改可能無法連接Redis,出現(xiàn)以下錯誤 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項(xiàng)目集成Redis
1、pom.xml添加依賴
<!-- Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2、Redis數(shù)據(jù)庫連接配置 application.yml
# Redis redis: # 服務(wù)器地址 host: 127.0.0.1 # 服務(wù)器端口號 port: 6379 # 使用的數(shù)據(jù)庫索引 database: 0 # 連接超時(shí)時(shí)間 timeout: 10000 # 設(shè)置密碼 password: ****** lettuce: # 連接池 pool: # 最大阻塞等待時(shí)間,負(fù)數(shù)表示沒有限制 max-wait: -1 # 連接池中最大空閑 max-idle: 5 # 連接池中最小空閑 min-idle: 0 # 連接池最大連接數(shù) 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相關(guān)配置 */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); // 配置連接工廠 template.setConnectionFactory(factory); //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(默認(rèn)使用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()); // 設(shè)置hash key 和value序列化模式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(jacksonSeial); template.afterPropertiesSet(); return template; } /** * 對hash類型的數(shù)據(jù)操作 */ @Bean public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForHash(); } /** * 對redis字符串類型數(shù)據(jù)操作 */ @Bean public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForValue(); } /** * 對鏈表類型的數(shù)據(jù)操作 */ @Bean public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForList(); } /** * 對無序集合類型的數(shù)據(jù)操作 */ @Bean public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForSet(); } /** * 對有序集合類型的數(shù)據(jù)操作 */ @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; } /** * 指定緩存失效時(shí)間 * * @param key 鍵 * @param time 時(shí)間(秒) * @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; } } /** * 根據(jù)key 獲取過期時(shí)間 * * @param key 鍵 不能為null * @return 時(shí)間(秒) 返回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; } } /** * 普通緩存放入并設(shè)置時(shí)間 * * @param key 鍵 * @param value 值 * @param time 時(shí)間(秒) time要大于0 如果time小于等于0 將設(shè)置無限期 * @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 項(xiàng) 不能為null * @return 值 */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 獲取hashKey對應(yīng)的所有鍵值 * * @param key 鍵 * @return 對應(yīng)的多個鍵值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * * @param key 鍵 * @param map 對應(yīng)多個鍵值 * @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 并設(shè)置時(shí)間 * * @param key 鍵 * @param map 對應(yīng)多個鍵值 * @param time 時(shí)間(秒) * @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表中放入數(shù)據(jù),如果不存在將創(chuàng)建 * * @param key 鍵 * @param item 項(xiàng) * @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表中放入數(shù)據(jù),如果不存在將創(chuàng)建 * * @param key 鍵 * @param item 項(xiàng) * @param value 值 * @param time 時(shí)間(秒) 注意:如果已存在的hash表有時(shí)間,這里將會替換原有的時(shí)間 * @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 項(xiàng) 可以使多個 不能為null */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * 判斷hash表中是否有該項(xiàng)的值 * * @param key 鍵 不能為null * @param item 項(xiàng) 不能為null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash遞增 如果不存在,就會創(chuàng)建一個 并把新增后的值返回 * * @param key 鍵 * @param item 項(xiàng) * @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 項(xiàng) * @param by 要減少記(小于0) * @return */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } //============================set============================= /** * 根據(jù)key獲取Set中的所有值 * * @param key 鍵 * @return */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根據(jù)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; } } /** * 將數(shù)據(jù)放入set緩存 * * @param key 鍵 * @param values 值 可以是多個 * @return 成功個數(shù) */ public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 將set數(shù)據(jù)放入緩存 * * @param key 鍵 * @param time 時(shí)間(秒) * @param values 值 可以是多個 * @return 成功個數(shù) */ 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 移除的個數(shù) */ 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緩存的內(nèi)容 * * @param key 鍵 * @param start 開始 * @param end 結(jié)束 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時(shí), 0 表頭,1 第二個元素,依次類推;index<0時(shí),-1,表尾,-2倒數(shù)第二個元素,依次類推 * @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 時(shí)間(秒) * @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 時(shí)間(秒) * @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; } } /** * 根據(jù)索引修改list中的某條數(shù)據(jù) * * @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 移除的個數(shù) */ 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項(xiàng)目集成log4j2
SpringBoot項(xiàng)目在運(yùn)行的時(shí)候可能會產(chǎn)生一些運(yùn)行信息,如果能將這些信息記錄下來,那么對于該項(xiàng)目的運(yùn)行狀態(tài)以及錯誤排查會起到一個非常好的幫助,所以采用log4j2進(jìn)行日志記錄
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> <!-- 每隔一天轉(zhuǎn)存 --> <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> <!-- 每隔一天轉(zhuǎn)存 --> <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> <!-- 每隔一天轉(zhuǎn)存 --> <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對類進(jìn)行注解,然后在類中使用log的方法即可,以該網(wǎng)站的數(shù)據(jù)庫讀取過程為例
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層(實(shí)現(xiàn)類) */ @Log4j2 @Service public class EmperorServiceImpl implements EmperorService { @Resource EmperorMapper emperorMapper; @Resource DynastyMapper dynastyMapper; @Resource RedisUtil redisUtil; /** * 獲得所有EmperorVo對象列表 * * @return */ @Override public List<EmperorVo> getAllEmperorVoList() { // 判斷Redis是否存在該結(jié)果 String key = "getAllEmperorVoList"; if (redisUtil.hasKey(key)) { List<EmperorVo> emperorVoList = (List<EmperorVo>) redisUtil.get(key); System.out.println("由Redis得到" + key + "結(jié)果"); // 日志記錄 log.info(new Date() + " 由Redis得到" + key + "數(shù)據(jù)"); 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 + "結(jié)果"); // 日志記錄 log.info(new Date() + " 由MySQL得到" + key + "數(shù)據(jù)"); if (redisUtil.set(key, emperorVoList, 600)) { System.out.println("Redis已存入" + key + "數(shù)據(jù)"); // 日志記錄 log.info(new Date() + " Redis已存入" + key + "數(shù)據(jù)"); } return emperorVoList; } /** * 根據(jù)id獲得EmperorVo對象 * * @param id * @return */ @Override public EmperorVo getEmperorVoById(Integer id) { // 判斷Redis是否存在該結(jié)果 String key = "getEmperorVoById_" + String.valueOf(id); if (redisUtil.hasKey(key)) { EmperorVo emperorVo = (EmperorVo) redisUtil.get(key); System.out.println("由Redis得到" + key + "結(jié)果"); // 日志記錄 log.info(new Date() + " 由Redis得到" + key + "數(shù)據(jù)"); 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 + "結(jié)果"); // 日志記錄 log.info(new Date() + " 由MySQL得到" + key + "數(shù)據(jù)"); if (redisUtil.set(key, emperorVo, 600)) { System.out.println("Redis已存入" + key + "數(shù)據(jù)"); // 日志記錄 log.info(new Date() + " Redis已存入" + key + "數(shù)據(jù)"); } return emperorVo; } /** * 根據(jù)dynastyId獲得所有EmperorVo對象列表 * * @param dynastyId * @return */ @Override public List<EmperorVo> getEmperorListByDynastyId(Integer dynastyId) { // 判斷Redis是否存在該結(jié)果 String key = "getEmperorListByDynastyId_" + String.valueOf(dynastyId); if (redisUtil.hasKey(key)) { List<EmperorVo> emperorVoList = (List<EmperorVo>) redisUtil.get(key); System.out.println("由Redis得到" + key + "結(jié)果"); // 日志記錄 log.info(new Date() + " 由Redis得到" + key + "數(shù)據(jù)"); 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 + "結(jié)果"); // 日志記錄 log.info(new Date() + " 由MySQL得到" + key + "數(shù)據(jù)"); if (redisUtil.set(key, emperorVoList, 600)) { System.out.println("Redis已存入" + key + "數(shù)據(jù)"); // 日志記錄 log.info(new Date() + " Redis已存入" + key + "數(shù)據(jù)"); } return emperorVoList; } }
以“getEmperorListByDynastyId(Integer dynastyId)”方法為例,該方法是根據(jù)dynastyId獲得List對象,首先會根據(jù)方法名及dynastyId在Redis數(shù)據(jù)庫中查找,若存在則直接返回,否則從MySQL數(shù)據(jù)庫中讀取,并將結(jié)果存入Redis數(shù)據(jù)庫中然后返回。使用log.info()記錄數(shù)據(jù)庫讀取過程,該記錄會存儲于info.log文件中
該網(wǎng)站后臺的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數(shù)據(jù)
[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數(shù)據(jù)
[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數(shù)據(jù)
[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數(shù)據(jù)
[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數(shù)據(jù)
[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數(shù)據(jù)
[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數(shù)據(jù)
[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數(shù)據(jù)
四、總結(jié)
關(guān)于SpringBoot項(xiàng)目配置Redis與log4j2是查詢官方文檔以及他人博客得到的,本文中的Redis配置類、Redis工具類以及l(fā)og4j2.xml配置文件來自網(wǎng)絡(luò),查證源自何處比較麻煩,所以在此感謝所有人的分享!
到此這篇關(guān)于Linux服務(wù)器使用Redis作為數(shù)據(jù)緩存,并用log4j2進(jìn)行日志記錄的文章就介紹到這了,更多相關(guān)Redis數(shù)據(jù)緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Redis實(shí)現(xiàn)優(yōu)惠券限一單限制詳解
這篇文章主要介紹了Redis解決優(yōu)惠券秒殺應(yīng)用案例,本文先講了搶購問題,指出其中會出現(xiàn)的多線程問題,提出解決方案采用悲觀鎖和樂觀鎖兩種方式進(jìn)行實(shí)現(xiàn),然后發(fā)現(xiàn)在搶購過程中容易出現(xiàn)一人多單現(xiàn)象,需要的朋友可以參考下2022-12-12實(shí)現(xiàn)在線?+?離線模式進(jìn)行遷移?Redis?數(shù)據(jù)實(shí)戰(zhàn)指南
這篇文章主要介紹了實(shí)現(xiàn)在線?+?離線模式進(jìn)行遷移?Redis?數(shù)據(jù)實(shí)戰(zhàn)指南的相關(guān)資料,需要的朋友可以參考下2023-01-01解讀Redis秒殺優(yōu)化方案(阻塞隊(duì)列+基于Stream流的消息隊(duì)列)
該文章介紹了使用Redis的阻塞隊(duì)列和Stream流的消息隊(duì)列來優(yōu)化秒殺系統(tǒng)的方案,通過將秒殺流程拆分為兩條流水線,使用Redis緩存緩解數(shù)據(jù)庫壓力,并結(jié)合Lua腳本進(jìn)行原子性判斷,使用阻塞隊(duì)列和消息隊(duì)列異步處理訂單,有效提高了系統(tǒng)的并發(fā)處理能力和可用性2025-02-02Redis increment 函數(shù)處理并發(fā)序列號案例
這篇文章主要介紹了Redis increment 函數(shù)處理并發(fā)序列號案例,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08