使用SpringBoot實(shí)現(xiàn)Redis多數(shù)據(jù)庫緩存
Redis多數(shù)據(jù)庫存儲實(shí)現(xiàn)用戶行為緩存
在我的系統(tǒng)中,為了優(yōu)化用戶行為數(shù)據(jù)的存儲與訪問效率,我引入了Redis緩存,并將數(shù)據(jù)分布在不同的Redis數(shù)據(jù)庫中。通過這種方式,可以減少單一數(shù)據(jù)庫的負(fù)載,提高系統(tǒng)的整體性能。
主要實(shí)現(xiàn)步驟
Redis配置
- 配置兩個(gè)Redis連接工廠,分別用于存儲Token和用戶行為數(shù)據(jù)。
- 創(chuàng)建對應(yīng)的RedisTemplate實(shí)例,指定不同的連接工廠及序列化方式。
用戶行為服務(wù)
- 通過
UserBehaviorService接口及其實(shí)現(xiàn)類UserBehaviorServiceImpl,實(shí)現(xiàn)對用戶點(diǎn)贊、收藏、評論、瀏覽行為的記錄。 - 在操作數(shù)據(jù)庫的同時(shí),將用戶行為數(shù)據(jù)存儲到Redis中以提高讀取效率。
- 通過
Token攔截器
- 使用
TokenInterceptor類在每次請求前驗(yàn)證Token。 - 驗(yàn)證通過后,將用戶信息存儲到
ThreadLocal中,供后續(xù)操作使用。
- 使用
代碼實(shí)現(xiàn)
Redis配置類
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String redisHost;
@Value("${spring.data.redis.port}")
private int redisPort;
@Value("${spring.data.redis.password}")
private String redisPassword;
@Bean(name = "tokenRedisConnectionFactory")
public RedisConnectionFactory tokenRedisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
config.setPassword(redisPassword);
config.setDatabase(0);
return new LettuceConnectionFactory(config);
}
@Bean(name = "userBehaviorRedisConnectionFactory")
public RedisConnectionFactory userBehaviorRedisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(redisHost, redisPort);
config.setPassword(redisPassword);
config.setDatabase(1);
return new LettuceConnectionFactory(config);
}
@Bean(name = "redisTemplate")
public StringRedisTemplate redisTemplate(@Qualifier("tokenRedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
@Bean(name = "userBehaviorRedisTemplate")
public RedisTemplate<String, Map<String, Integer>> userBehaviorRedisTemplate(@Qualifier("userBehaviorRedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Map<String, Integer>> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Map.class));
return template;
}
}
用戶行為服務(wù)實(shí)現(xiàn)類
@Service
public class UserBehaviorServiceImpl implements UserBehaviorService {
private static final long CACHE_EXPIRATION_DAYS = 1;
private static final String CACHE_PREFIX = "articleCounts:";
@Autowired
private UserBehaviorMapper userBehaviorMapper;
@Autowired
@Qualifier("userBehaviorRedisTemplate")
private RedisTemplate<String, Map<String, Integer>> userBehaviorRedisTemplate;
@Override
public void setLikeArticle(Likes likes) {
likes.setCreateTime(LocalDateTime.now());
Integer userId = ThreadLocalUtil.getUser("id");
if (userId != null) {
likes.setUserId(userId);
}
userBehaviorMapper.insertLike(likes);
}
@Override
public void setFavoriteArticle(Favorites favorites) {
favorites.setCreateTime(LocalDateTime.now());
Integer userId = ThreadLocalUtil.getUser("id");
if (userId != null) {
favorites.setUserId(userId);
}
userBehaviorMapper.insertFavorite(favorites);
}
@Override
public void setCommentArticle(Comments comments) {
comments.setCreateTime(LocalDateTime.now());
Integer userId = ThreadLocalUtil.getUser("id");
if (userId != null) {
comments.setUserId(userId);
}
userBehaviorMapper.insertComment(comments);
}
@Override
public void setViewArticle(Views views) {
views.setCreateTime(LocalDateTime.now());
Integer userId = ThreadLocalUtil.getUser("id");
if (userId != null) {
views.setUserId(userId);
}
userBehaviorMapper.insertView(views);
}
@Override
public Map<String, Integer> getArticleCounts(Integer articleId) {
String key = CACHE_PREFIX + articleId;
Map<String, Integer> counts = userBehaviorRedisTemplate.opsForValue().get(key);
if (counts == null) {
counts = fetchArticleCountsFromDB(articleId);
cacheArticleCounts(articleId, counts);
}
return counts;
}
private Map<String, Integer> fetchArticleCountsFromDB(Integer articleId) {
Map<String, Integer> counts = new HashMap<>();
counts.put("likesCount", userBehaviorMapper.selectLikesCount(articleId));
counts.put("favoritesCount", userBehaviorMapper.selectFavoritesCount(articleId));
counts.put("commentsCount", userBehaviorMapper.selectCommentsCount(articleId));
counts.put("viewsCount", userBehaviorMapper.selectViewsCount(articleId));
return counts;
}
private void cacheArticleCounts(Integer articleId, Map<String, Integer> counts) {
String key = CACHE_PREFIX + articleId;
userBehaviorRedisTemplate.opsForValue().set(key, counts, CACHE_EXPIRATION_DAYS, TimeUnit.DAYS);
}
}
Token攔截器
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || token.isEmpty()) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
try {
ValueOperations<String, String> operations = redisTemplate.opsForValue();
String redisToken = operations.get(token);
if (redisToken == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
Map<String, Object> claims = JwtUtil.parseToken(token);
ThreadLocalUtil.setUser(claims);
return true;
} catch (Exception e) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
}
@Override
public void postHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception {
ThreadLocalUtil.remove();
}
}
到此這篇關(guān)于使用SpringBoot實(shí)現(xiàn)Redis多數(shù)據(jù)庫緩存的文章就介紹到這了,更多相關(guān)SpringBoot Redis數(shù)據(jù)緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 序列化詳解及簡單實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了 Java 序列化詳解及簡單實(shí)現(xiàn)實(shí)例的相關(guān)資料,使用序列化目的:以某種存儲形式使自定義對象持久化,將對象從一個(gè)地方傳遞到另一個(gè)地方,需要的朋友可以參考下2017-03-03
Java實(shí)現(xiàn)PDF文件的分割與加密功能
這篇文章主要為大家分享了如何利用Java語言實(shí)現(xiàn)PDF文件的分割與加密以及封面圖的生成,文中的示例代碼簡潔易懂,感興趣的可以了解一下2022-04-04
Java實(shí)現(xiàn)解壓zip壓縮包的兩種方法(支持多層級)
壓縮文件在生活中經(jīng)常能用到,在Java中提供了壓縮和解壓縮文件的功能,本文主要介紹了Java實(shí)現(xiàn)解壓zip壓縮包的兩種方法(支持多層級),感興趣的可以了解一下2024-03-03
SpringBoot實(shí)現(xiàn)微服務(wù)通信的多種方式
微服務(wù)通信是指在分布式系統(tǒng)中,各個(gè)微服務(wù)之間進(jìn)行數(shù)據(jù)交互和通信的過程,今天我們將探討在Spring Boot中實(shí)現(xiàn)微服務(wù)通信的多種方式,文章通過代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-07-07
Java利用條件運(yùn)算符的嵌套來完成學(xué)習(xí)成績的劃分
這篇文章主要介紹了Java利用條件運(yùn)算符的嵌套來完成學(xué)習(xí)成績的劃分,需要的朋友可以參考下2017-02-02

