Compare commits

...
3 Commits
Author SHA1 Message Date
wonder 8cd2000274 📝Docs: 增加关于类型转换的解释 2025-10-20 20:53:42 +08:00
wonder 37ea93e923 ♻️Refactor: 优化值获取的判空逻辑 2025-10-20 20:44:27 +08:00
wonder 06f72e5bee 📝Docs: 增加关于序列化的说明 2025-10-20 20:36:24 +08:00
2 changed files with 42 additions and 11 deletions
+40 -9
View File
@@ -29,31 +29,62 @@
## QA
1. 如何从数据库层面杜绝重复数据出现?
> Q1. _联合唯一索引_ | 如何从数据库层面杜绝重复数据出现?
答:对于 `thumb` 表,使用联合唯一索引
对于 `thumb` 表,使用联合唯一索引
```mysql
CREATE UNIQUE INDEX idx_userId_blogId ON thumb (userId, blogId);
```
2. 为什么要在 `BlogServiceImpl` 导入 `ThumbService` 上加 `@Lazy`
---
> Q2. _循环依赖_ | 为什么要在 `BlogServiceImpl` 导入 `ThumbService` 上加 `@Lazy`
答:
- 博客服务中需要使用点赞服务查询博客对应的点赞情况列表以返回对应视图。
- 点赞服务中需要使用博客服务更新单条博客的点赞计数器。
- 两个服务之间产生了**循环依赖**,Spring Boot 2.6 以后的版本默认不允许循环依赖,这里可以使用懒加载的方式避免这一问题。
3. 点赞接口加锁对象是什么?
---
> Q3. _锁_ | 点赞接口加锁对象是什么?对用户加锁还是对帖子加锁?
答:
- 加锁目的是为了避免用户并发请求造成数据不一致。
- 不能对帖子加锁,因为帖子是全局的,加锁会导致其他用户无法点赞。
- 因此需要对用户加锁,故而实际上是将每个用户的 id 当作锁。
4. 点赞接口的锁具体如何处理?
答:
`synchronized (("LOCK-USERID-" + loginUser.getId().toString()).intern()) `
---
> Q4. _字符串对象锁_ | 点赞接口的锁具体如何处理?
- `synchronized (("LOCK-USERID-" + loginUser.getId().toString()).intern()) `
- 每个用户持有一个唯一 id,因此考虑把 id 对应的 String 常量池对象加锁。
- 为了避免对程序中其他需要使用该字符串常量的地方产生影响,这里对字符串作出处理 `"LOCK-USERID-" + loginUser.getId().toString()`
- 并且我们需要将字符串放到常量池中,调用 `intern()` 方法。
---
> Q5. _序列化_ | 对于 Redis 数据的存储使用序列化是怎么样的?
- `key` 和 `hash filed` 使用 String 类型,`value` 使用 Object 类型。
- `value` 为 `Long` 或者 `Integer` 类型时,优先进行以下操作——
- 存储时转化为 `String` 类型
- 取出时转化为 `Long` 或者 `Integer` 类型
- (注意转化前需要先判空,避免空指针)
---
> Q6. _类型转换_ | `Object` 向 `Long` 的转化优化方式
- 方法 A
- `Long.valueOf(object.toString())`
- 注意:`object` 为非数字字符串时会抛出 `NumberFormatException``
- 方法 B
- `((Number) object).longValue() `
- 注意:`object` 为非数字字符串时会抛出 `ClassCastException``
- 比较
- 方法 B 优于方法 A
- 方法 A 需要调用 `toString()` 方法,有额外开销
- 方法 B 直接调用 `longValue()` 方法,`JVM` 优化
- 方法 B 抛出的异常容易定位问题。
@@ -88,10 +88,10 @@ public class ThumbServiceImpl extends ServiceImpl<ThumbMapper, Thumb>
Long blogId = doThumbRequest.getBlogId();
// 判断是否已点过赞
Object thumbIdObj = redisTemplate.opsForHash().get(ThumbConstant.USER_THUMB_KEY_PREFIX + loginUser.getId().toString(), blogId.toString());
Long thumbId = thumbIdObj == null ? null : ((Number) thumbIdObj).longValue();
if (thumbId == null) {
if (thumbIdObj == null) {
throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户未点赞");
}
Long thumbId = ((Number) thumbIdObj).longValue();
// 更新帖子点赞计数器
boolean update = blogService.lambdaUpdate()
.eq(Blog::getId, blogId)