Compare commits

..
2 Commits
Author SHA1 Message Date
wonder 1410f4be36 ✨Feat: 使用Redis优化点赞查询性能 2025-10-20 14:01:31 +08:00
wonder f00aae2651 🔄Update: 添加Redis配置和依赖 2025-10-19 14:40:17 +08:00
7 changed files with 126 additions and 27 deletions
+21
View File
@@ -67,6 +67,27 @@
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>lettuce-core</groupId>
<artifactId>io.lettuce</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
</dependencies> </dependencies>
@@ -0,0 +1,42 @@
package cn.hezhaohui.thumb.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
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.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 对象 序列化
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
// Key
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}
@@ -0,0 +1,15 @@
package cn.hezhaohui.thumb.constent;
/**
* 点赞常量接口
* 用于定义与点赞功能相关的常量
*/
public interface ThumbConstant {
/**
* 用户点赞前缀常量
* 用于作为Redis中存储用户点赞信息的key前缀
*/
String USER_THUMB_KEY_PREFIX = "thumb:";
}
@@ -16,4 +16,6 @@ public interface ThumbService extends IService<Thumb> {
Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request); Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request);
Boolean undoThumb(DoThumbRequest doThumbRequest, HttpServletRequest request); Boolean undoThumb(DoThumbRequest doThumbRequest, HttpServletRequest request);
Boolean hasThumb(Long blogId, Long userId);
} }
@@ -1,6 +1,6 @@
package cn.hezhaohui.thumb.service.impl; package cn.hezhaohui.thumb.service.impl;
import cn.hezhaohui.thumb.model.entity.Thumb; import cn.hezhaohui.thumb.constent.ThumbConstant;
import cn.hezhaohui.thumb.model.entity.User; import cn.hezhaohui.thumb.model.entity.User;
import cn.hezhaohui.thumb.model.vo.BlogVO; import cn.hezhaohui.thumb.model.vo.BlogVO;
import cn.hezhaohui.thumb.service.ThumbService; import cn.hezhaohui.thumb.service.ThumbService;
@@ -14,12 +14,12 @@ import cn.hezhaohui.thumb.mapper.BlogMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -38,9 +38,8 @@ public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog>
@Lazy @Lazy
private ThumbService thumbService; private ThumbService thumbService;
public BlogServiceImpl(UserService userService) { @Resource
this.userService = userService; private RedisTemplate<String, Object> redisTemplate;
}
@Override @Override
public BlogVO getBlogVOById(long blogId, HttpServletRequest request) { public BlogVO getBlogVOById(long blogId, HttpServletRequest request) {
@@ -55,13 +54,15 @@ public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog>
Map<Long, Boolean> blogIdHasThumbMap = new HashMap<>(); Map<Long, Boolean> blogIdHasThumbMap = new HashMap<>();
if (ObjUtil.isNotEmpty(loginUser)) { if (ObjUtil.isNotEmpty(loginUser)) {
// Blog Id // Blog Id
Set<Long> blogIdSet = blogList.stream().map(Blog::getId).collect(Collectors.toSet()); List<Object> blogIdList = blogList.stream().map(blog -> blog.getId().toString()).collect(Collectors.toList());
// Get Thumb-up Data // Get Thumb-up Data
List<Thumb> thumbList = thumbService.lambdaQuery() List<Object> thumbList = redisTemplate.opsForHash().multiGet(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogIdList);
.eq(Thumb::getUserid, loginUser.getId()) for (int i = 0; i < thumbList.size(); i++) {
.in(Thumb::getBlogId, blogIdSet) if (thumbList.get(i) == null) {
.list(); continue;
thumbList.forEach(blogThumb -> blogIdHasThumbMap.put(blogThumb.getBlogId(), true)); }
blogIdHasThumbMap.put(Long.valueOf(blogIdList.get(i).toString()), true);
}
} }
return blogList.stream() return blogList.stream()
.map(blog -> { .map(blog -> {
@@ -80,11 +81,8 @@ public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog>
return blogVO; return blogVO;
} }
Thumb thumb = thumbService.lambdaQuery() Boolean exist = thumbService.hasThumb(blog.getId(), loginUser.getId());
.eq(Thumb::getUserid, loginUser.getId()) blogVO.setHasThumb(exist);
.eq(Thumb::getBlogId, blog.getId())
.one();
blogVO.setHasThumb(thumb != null);
return blogVO; return blogVO;
} }
@@ -1,5 +1,6 @@
package cn.hezhaohui.thumb.service.impl; package cn.hezhaohui.thumb.service.impl;
import cn.hezhaohui.thumb.constent.ThumbConstant;
import cn.hezhaohui.thumb.exception.BusinessException; import cn.hezhaohui.thumb.exception.BusinessException;
import cn.hezhaohui.thumb.exception.ErrorCode; import cn.hezhaohui.thumb.exception.ErrorCode;
import cn.hezhaohui.thumb.model.dto.DoThumbRequest; import cn.hezhaohui.thumb.model.dto.DoThumbRequest;
@@ -13,6 +14,7 @@ import cn.hezhaohui.thumb.service.ThumbService;
import cn.hezhaohui.thumb.mapper.ThumbMapper; import cn.hezhaohui.thumb.mapper.ThumbMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
@@ -34,6 +36,9 @@ public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
@Resource @Resource
private TransactionTemplate transactionTemplate; private TransactionTemplate transactionTemplate;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Override @Override
public Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) { public Boolean doThumb(DoThumbRequest doThumbRequest, HttpServletRequest request) {
if (doThumbRequest == null || doThumbRequest.getBlogId() == null) { if (doThumbRequest == null || doThumbRequest.getBlogId() == null) {
@@ -46,10 +51,7 @@ public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
return transactionTemplate.execute(status -> { return transactionTemplate.execute(status -> {
Long blogId = doThumbRequest.getBlogId(); Long blogId = doThumbRequest.getBlogId();
// 判断是否已点过赞 // 判断是否已点过赞
boolean exists = this.lambdaQuery() Boolean exists = this.hasThumb(blogId, loginUser.getId());
.eq(Thumb::getUserid, loginUser.getId())
.eq(Thumb::getBlogId, blogId)
.exists();
if (exists) { if (exists) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户已点赞"); throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户已点赞");
} }
@@ -63,7 +65,12 @@ public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
thumb.setUserid(loginUser.getId()); thumb.setUserid(loginUser.getId());
thumb.setBlogId(blogId); thumb.setBlogId(blogId);
// 两者一起执行 // 两者一起执行
return update && this.save(thumb); boolean success = update && this.save(thumb);
// 点赞记录存入 Redis
if (success) {
redisTemplate.opsForHash().put(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId().toString(), blogId.toString(), thumb.getId());
}
return success;
}); });
} }
} }
@@ -80,11 +87,9 @@ public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
return transactionTemplate.execute(status -> { return transactionTemplate.execute(status -> {
Long blogId = doThumbRequest.getBlogId(); Long blogId = doThumbRequest.getBlogId();
// 判断是否已点过赞 // 判断是否已点过赞
Thumb thumb = this.lambdaQuery() Object thumbIdObj = redisTemplate.opsForHash().get(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId().toString(), blogId.toString());
.eq(Thumb::getUserid, loginUser.getId()) Long thumbId = thumbIdObj == null ? null : ((Number) thumbIdObj).longValue();
.eq(Thumb::getBlogId, blogId) if (thumbId == null) {
.one();
if (thumb == null) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户未点赞"); throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户未点赞");
} }
// 更新帖子点赞计数器 // 更新帖子点赞计数器
@@ -94,10 +99,19 @@ public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
.update(); .update();
// 更新点赞表数据 // 更新点赞表数据
// 两者一起执行 // 两者一起执行
return update && this.removeById(thumb.getId()); boolean success = update && this.removeById(thumbId);
if (success) {
redisTemplate.opsForHash().delete(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId(), blogId.toString());
}
return success;
}); });
} }
} }
@Override
public Boolean hasThumb(Long blogId, Long userId) {
return redisTemplate.opsForHash().hasKey(ThumbConstant.USER_THUMB_KEY_PREFIX + userId, blogId.toString());
}
} }
+7
View File
@@ -9,6 +9,13 @@ spring:
url: jdbc:mysql://47.121.181.112:3306/thumb_up url: jdbc:mysql://47.121.181.112:3306/thumb_up
username: root username: root
password: dn293830 password: dn293830
data:
redis:
database: 0
host: 47.121.181.112
port: 6379
password: dn293830
connect-timeout: 5000
mybatis-plus: mybatis-plus: