21 changed files with 725 additions and 52 deletions
@ -1,40 +0,0 @@ |
|||||
package com.youlai.boot.mini.job; |
|
||||
|
|
||||
import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteCommentMapper; |
|
||||
import lombok.RequiredArgsConstructor; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.springframework.scheduling.annotation.Scheduled; |
|
||||
import org.springframework.stereotype.Component; |
|
||||
import org.springframework.transaction.annotation.Transactional; |
|
||||
|
|
||||
/** |
|
||||
* 评论计数校准定时任务 |
|
||||
* <p> |
|
||||
* 定时校准评论数量 |
|
||||
*/ |
|
||||
@Component |
|
||||
@Slf4j |
|
||||
@RequiredArgsConstructor |
|
||||
public class CommentCountCalibrateJob { |
|
||||
|
|
||||
private final MiniStrayAnimalNoteCommentMapper miniStrayAnimalNoteCommentMapper; |
|
||||
|
|
||||
// 每天凌晨 00:00:00 执行
|
|
||||
@Scheduled(cron = "0 0 0 * * ?") |
|
||||
@Transactional |
|
||||
public void calibrateCommentCounts() { |
|
||||
log.info("开始校准动物笔记评论数..."); |
|
||||
long startTime = System.currentTimeMillis(); |
|
||||
|
|
||||
try { |
|
||||
int updatedCount = miniStrayAnimalNoteCommentMapper.batchCalibrateAllCommentCounts(); |
|
||||
// 方案B:增量校准(数据量大时使用)
|
|
||||
long costTime = System.currentTimeMillis() - startTime; |
|
||||
log.info("校准完成,共更新 {} 条笔记,耗时 {} ms", updatedCount, costTime); |
|
||||
} catch (Exception e) { |
|
||||
log.error("校准失败", e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
} |
|
||||
@ -0,0 +1,108 @@ |
|||||
|
package com.youlai.boot.mini.job; |
||||
|
|
||||
|
import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteCommentMapper; |
||||
|
import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteMapper; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
/** |
||||
|
* 动物笔记统计数据校准定时任务 |
||||
|
* <p> |
||||
|
* 定时校准评论数、点赞数、收藏数,防止并发操作导致计数不准确 |
||||
|
*/ |
||||
|
@Component |
||||
|
@Slf4j |
||||
|
@RequiredArgsConstructor |
||||
|
public class NoteStatsCalibrateJob { |
||||
|
|
||||
|
private final MiniStrayAnimalNoteCommentMapper miniStrayAnimalNoteCommentMapper; |
||||
|
private final MiniStrayAnimalNoteMapper miniStrayAnimalNoteMapper; |
||||
|
|
||||
|
/** |
||||
|
* 校准所有统计数据 |
||||
|
* 每天凌晨 00:00:00 执行 |
||||
|
*/ |
||||
|
@Scheduled(cron = "0 0 0 * * ?") |
||||
|
// @Scheduled(cron = "0 */1 * * * ?")
|
||||
|
@Transactional |
||||
|
public void calibrateAllStats() { |
||||
|
log.info("========== 开始校准动物笔记统计数据 =========="); |
||||
|
long totalStartTime = System.currentTimeMillis(); |
||||
|
|
||||
|
calibrateCommentCounts(); |
||||
|
calibrateCommentLikeCounts(); |
||||
|
calibrateNoteLikeCounts(); |
||||
|
calibrateCollectCounts(); |
||||
|
|
||||
|
long totalCostTime = System.currentTimeMillis() - totalStartTime; |
||||
|
log.info("========== 全部统计数据校准完成,总耗时 {} ms ==========", totalCostTime); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校准笔记评论数 |
||||
|
*/ |
||||
|
private void calibrateCommentCounts() { |
||||
|
log.info("开始校准动物笔记评论数..."); |
||||
|
long startTime = System.currentTimeMillis(); |
||||
|
|
||||
|
try { |
||||
|
int updatedCount = miniStrayAnimalNoteCommentMapper.batchCalibrateAllCommentCounts(); |
||||
|
long costTime = System.currentTimeMillis() - startTime; |
||||
|
log.info("校准评论数完成,共更新 {} 条笔记,耗时 {} ms", updatedCount, costTime); |
||||
|
} catch (Exception e) { |
||||
|
log.error("校准评论数失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校准评论点赞数 |
||||
|
*/ |
||||
|
private void calibrateCommentLikeCounts() { |
||||
|
log.info("开始校准评论点赞数..."); |
||||
|
long startTime = System.currentTimeMillis(); |
||||
|
|
||||
|
try { |
||||
|
int updatedCount = miniStrayAnimalNoteCommentMapper.batchCalibrateAllCommentLikeCounts(); |
||||
|
long costTime = System.currentTimeMillis() - startTime; |
||||
|
log.info("校准评论点赞数完成,共更新 {} 条评论,耗时 {} ms", updatedCount, costTime); |
||||
|
} catch (Exception e) { |
||||
|
log.error("校准评论点赞数失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校准笔记点赞数 |
||||
|
*/ |
||||
|
private void calibrateNoteLikeCounts() { |
||||
|
log.info("开始校准动物笔记点赞数..."); |
||||
|
long startTime = System.currentTimeMillis(); |
||||
|
|
||||
|
try { |
||||
|
int updatedCount = miniStrayAnimalNoteMapper.batchCalibrateAllLikeCounts(); |
||||
|
long costTime = System.currentTimeMillis() - startTime; |
||||
|
log.info("校准点赞数完成,共更新 {} 条笔记,耗时 {} ms", updatedCount, costTime); |
||||
|
} catch (Exception e) { |
||||
|
log.error("校准点赞数失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校准笔记收藏数 |
||||
|
*/ |
||||
|
private void calibrateCollectCounts() { |
||||
|
log.info("开始校准动物笔记收藏数..."); |
||||
|
long startTime = System.currentTimeMillis(); |
||||
|
|
||||
|
try { |
||||
|
int updatedCount = miniStrayAnimalNoteMapper.batchCalibrateAllCollectCounts(); |
||||
|
long costTime = System.currentTimeMillis() - startTime; |
||||
|
log.info("校准收藏数完成,共更新 {} 条笔记,耗时 {} ms", updatedCount, costTime); |
||||
|
} catch (Exception e) { |
||||
|
log.error("校准收藏数失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
package com.youlai.boot.mini.mapper; |
||||
|
|
||||
|
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteCollect; |
||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
/** |
||||
|
* 用户收藏表 Mapper 接口 |
||||
|
* |
||||
|
* @author jwy |
||||
|
* @since |
||||
|
*/ |
||||
|
public interface MiniStrayAnimalNoteCollectMapper extends BaseMapper<MiniStrayAnimalNoteCollect> { |
||||
|
|
||||
|
/** |
||||
|
* 查询用户是否收藏该笔记 |
||||
|
*/ |
||||
|
Integer selectUserCollectCount(@Param("noteId") Long noteId, @Param("userId") Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 新增或更新收藏记录(原子操作) |
||||
|
*/ |
||||
|
int insertOrUpdateCollect(MiniStrayAnimalNoteCollect collect); |
||||
|
|
||||
|
/** |
||||
|
* 逻辑删除收藏记录(取消收藏) |
||||
|
*/ |
||||
|
int deleteCollect(@Param("noteId") Long noteId, @Param("userId") Long userId, @Param("currentTime") Long currentTime); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
package com.youlai.boot.mini.mapper; |
||||
|
|
||||
|
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteLike; |
||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
|
import org.apache.ibatis.annotations.Param; |
||||
|
|
||||
|
/** |
||||
|
* 流浪动物笔记点赞表 Mapper 接口 |
||||
|
* |
||||
|
* @author jwy |
||||
|
* @since |
||||
|
*/ |
||||
|
public interface MiniStrayAnimalNoteLikeMapper extends BaseMapper<MiniStrayAnimalNoteLike> { |
||||
|
|
||||
|
/** |
||||
|
* 查询用户是否点赞该笔记 |
||||
|
*/ |
||||
|
Integer selectUserLikeCount(@Param("noteId") Long noteId, @Param("userId") Long userId); |
||||
|
|
||||
|
/** |
||||
|
* 新增或更新点赞记录(原子操作) |
||||
|
*/ |
||||
|
int insertOrUpdateLike(MiniStrayAnimalNoteLike like); |
||||
|
|
||||
|
/** |
||||
|
* 逻辑删除点赞记录(取消点赞) |
||||
|
*/ |
||||
|
int deleteLike(@Param("noteId") Long noteId, @Param("userId") Long userId, @Param("currentTime") Long currentTime); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
package com.youlai.boot.mini.model.entity; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import lombok.ToString; |
||||
|
import lombok.experimental.Accessors; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.Date; |
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
|
||||
|
@Getter |
||||
|
@Setter |
||||
|
@ToString |
||||
|
@Accessors(chain = true) |
||||
|
@TableName("mini_stray_animal_note_collect") |
||||
|
@Schema(description = "用户收藏表") |
||||
|
public class MiniStrayAnimalNoteCollect implements Serializable { |
||||
|
|
||||
|
@TableId(value = "id", type = IdType.AUTO) |
||||
|
@Schema(description = "用户收藏表主键id") |
||||
|
private Long id; |
||||
|
|
||||
|
|
||||
|
@TableField("uuid") |
||||
|
@Schema(description = "uuid唯一标识,前后端用这个进行数据交互") |
||||
|
private String uuid; |
||||
|
|
||||
|
@TableField("note_id") |
||||
|
@Schema(description = "笔记id") |
||||
|
private Long noteId; |
||||
|
|
||||
|
@TableField("mini_user_id") |
||||
|
@Schema(description = "收藏用户id") |
||||
|
private Long miniUserId; |
||||
|
|
||||
|
@TableField("create_time") |
||||
|
@Schema(description = "创建时间") |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
private Date createTime; |
||||
|
|
||||
|
@TableField("create_timestamp") |
||||
|
@Schema(description = "创建时间毫秒级时间戳") |
||||
|
private Long createTimestamp; |
||||
|
|
||||
|
@TableField("create_by") |
||||
|
@Schema(description = "创建人ID") |
||||
|
private Long createBy; |
||||
|
|
||||
|
@TableField("update_time") |
||||
|
@Schema(description = "更新时间") |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
private Date updateTime; |
||||
|
|
||||
|
@TableField("update_timestamp") |
||||
|
@Schema(description = "更新时间毫秒级时间戳") |
||||
|
private Long updateTimestamp; |
||||
|
|
||||
|
@TableField("update_by") |
||||
|
@Schema(description = "修改人ID") |
||||
|
private Long updateBy; |
||||
|
|
||||
|
@TableField("is_deleted") |
||||
|
@Schema(description = "逻辑删除标识(0-未删除 1-已删除)") |
||||
|
private Boolean deleted; |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
package com.youlai.boot.mini.model.entity; |
||||
|
|
||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import lombok.Getter; |
||||
|
import lombok.Setter; |
||||
|
import lombok.ToString; |
||||
|
import lombok.experimental.Accessors; |
||||
|
|
||||
|
import java.io.Serializable; |
||||
|
import java.util.Date; |
||||
|
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
|
||||
|
@Getter |
||||
|
@Setter |
||||
|
@ToString |
||||
|
@Accessors(chain = true) |
||||
|
@TableName("mini_stray_animal_note_like") |
||||
|
@Schema(description = "流浪动物笔记点赞表") |
||||
|
public class MiniStrayAnimalNoteLike implements Serializable { |
||||
|
|
||||
|
@TableId(value = "id", type = IdType.AUTO) |
||||
|
@Schema(description = "流浪动物笔记点赞表主键id") |
||||
|
private Long id; |
||||
|
|
||||
|
|
||||
|
@TableField("uuid") |
||||
|
@Schema(description = "uuid唯一标识,前后端用这个进行数据交互") |
||||
|
private String uuid; |
||||
|
|
||||
|
@TableField("note_id") |
||||
|
@Schema(description = "笔记id") |
||||
|
private Long noteId; |
||||
|
|
||||
|
@TableField("mini_user_id") |
||||
|
@Schema(description = "点赞用户id") |
||||
|
private Long miniUserId; |
||||
|
|
||||
|
@TableField("create_time") |
||||
|
@Schema(description = "创建时间") |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
private Date createTime; |
||||
|
|
||||
|
@TableField("create_timestamp") |
||||
|
@Schema(description = "创建时间毫秒级时间戳") |
||||
|
private Long createTimestamp; |
||||
|
|
||||
|
@TableField("create_by") |
||||
|
@Schema(description = "创建人ID") |
||||
|
private Long createBy; |
||||
|
|
||||
|
@TableField("update_time") |
||||
|
@Schema(description = "更新时间") |
||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
|
private Date updateTime; |
||||
|
|
||||
|
@TableField("update_timestamp") |
||||
|
@Schema(description = "更新时间毫秒级时间戳") |
||||
|
private Long updateTimestamp; |
||||
|
|
||||
|
@TableField("update_by") |
||||
|
@Schema(description = "修改人ID") |
||||
|
private Long updateBy; |
||||
|
|
||||
|
@TableField("is_deleted") |
||||
|
@Schema(description = "逻辑删除标识(0-未删除 1-已删除)") |
||||
|
private Boolean deleted; |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
package com.youlai.boot.mini.model.form; |
||||
|
|
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
@Schema(description = "笔记收藏请求参数") |
||||
|
public class NoteCollectForm { |
||||
|
|
||||
|
@NotBlank(message = "笔记UUID不能为空") |
||||
|
@Schema(description = "笔记UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "a1b2c3d4e5f6g7h8i9j0") |
||||
|
private String noteUuid; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
package com.youlai.boot.mini.model.form; |
||||
|
|
||||
|
import io.swagger.v3.oas.annotations.media.Schema; |
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
@Schema(description = "笔记点赞请求参数") |
||||
|
public class NoteLikeForm { |
||||
|
|
||||
|
@NotBlank(message = "笔记UUID不能为空") |
||||
|
@Schema(description = "笔记UUID", requiredMode = Schema.RequiredMode.REQUIRED, example = "a1b2c3d4e5f6g7h8i9j0") |
||||
|
private String noteUuid; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
|
||||
|
<mapper namespace="com.youlai.boot.mini.mapper.MiniStrayAnimalNoteCollectMapper"> |
||||
|
|
||||
|
<!-- 查询用户是否收藏该笔记 --> |
||||
|
<select id="selectUserCollectCount" resultType="java.lang.Integer"> |
||||
|
SELECT COUNT(1) |
||||
|
FROM mini_stray_animal_note_collect |
||||
|
WHERE note_id = #{noteId} |
||||
|
AND mini_user_id = #{userId} |
||||
|
AND is_deleted = 0 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增或更新收藏记录(原子操作,依赖note_id和mini_user_id联合唯一索引) --> |
||||
|
<insert id="insertOrUpdateCollect" parameterType="com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteCollect"> |
||||
|
INSERT INTO mini_stray_animal_note_collect |
||||
|
(uuid, note_id, mini_user_id, create_time, create_timestamp, create_by, update_time, update_timestamp, update_by, is_deleted) |
||||
|
VALUES |
||||
|
(#{uuid}, #{noteId}, #{miniUserId}, #{createTime}, #{createTimestamp}, #{createBy}, #{updateTime}, #{updateTimestamp}, #{updateBy}, #{deleted}) |
||||
|
ON DUPLICATE KEY UPDATE |
||||
|
is_deleted = 0, |
||||
|
update_time = VALUES(update_time), |
||||
|
update_timestamp = VALUES(update_timestamp), |
||||
|
update_by = VALUES(update_by) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 逻辑删除收藏记录(取消收藏) --> |
||||
|
<update id="deleteCollect"> |
||||
|
UPDATE mini_stray_animal_note_collect |
||||
|
SET is_deleted = 1, |
||||
|
update_time = NOW(), |
||||
|
update_timestamp = #{currentTime}, |
||||
|
update_by = #{userId} |
||||
|
WHERE note_id = #{noteId} |
||||
|
AND mini_user_id = #{userId} |
||||
|
AND is_deleted = 0 |
||||
|
</update> |
||||
|
|
||||
|
</mapper> |
||||
@ -0,0 +1,42 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!DOCTYPE mapper |
||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
||||
|
|
||||
|
<mapper namespace="com.youlai.boot.mini.mapper.MiniStrayAnimalNoteLikeMapper"> |
||||
|
|
||||
|
<!-- 查询用户是否点赞该笔记 --> |
||||
|
<select id="selectUserLikeCount" resultType="java.lang.Integer"> |
||||
|
SELECT COUNT(1) |
||||
|
FROM mini_stray_animal_note_like |
||||
|
WHERE note_id = #{noteId} |
||||
|
AND mini_user_id = #{userId} |
||||
|
AND is_deleted = 0 |
||||
|
</select> |
||||
|
|
||||
|
<!-- 新增或更新点赞记录(原子操作,依赖note_id和mini_user_id联合唯一索引) --> |
||||
|
<insert id="insertOrUpdateLike" parameterType="com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteLike"> |
||||
|
INSERT INTO mini_stray_animal_note_like |
||||
|
(uuid, note_id, mini_user_id, create_time, create_timestamp, create_by, update_time, update_timestamp, update_by, is_deleted) |
||||
|
VALUES |
||||
|
(#{uuid}, #{noteId}, #{miniUserId}, #{createTime}, #{createTimestamp}, #{createBy}, #{updateTime}, #{updateTimestamp}, #{updateBy}, #{deleted}) |
||||
|
ON DUPLICATE KEY UPDATE |
||||
|
is_deleted = 0, |
||||
|
update_time = VALUES(update_time), |
||||
|
update_timestamp = VALUES(update_timestamp), |
||||
|
update_by = VALUES(update_by) |
||||
|
</insert> |
||||
|
|
||||
|
<!-- 逻辑删除点赞记录(取消点赞) --> |
||||
|
<update id="deleteLike"> |
||||
|
UPDATE mini_stray_animal_note_like |
||||
|
SET is_deleted = 1, |
||||
|
update_time = NOW(), |
||||
|
update_timestamp = #{currentTime}, |
||||
|
update_by = #{userId} |
||||
|
WHERE note_id = #{noteId} |
||||
|
AND mini_user_id = #{userId} |
||||
|
AND is_deleted = 0 |
||||
|
</update> |
||||
|
|
||||
|
</mapper> |
||||
Loading…
Reference in new issue