feat(repository): enhance repository methods with batch processing and transaction support
All checks were successful
Build Backend / build (push) Successful in 12m50s
Build Backend / build-docker (push) Successful in 2m57s

- Updated Like and Unlike methods in CommentRepository to use transactions for data consistency.
- Introduced IsLikedBatch method for batch checking if comments are liked, addressing N+1 query issues.
- Enhanced BatchDelete method in PostRepository to perform batch deletions within a single transaction, improving efficiency.
- Added BatchUpdateStatus method for posts to utilize a single SQL update for status changes, reducing database load.
- Implemented BatchUpdateSortOrder in StickerRepository using CASE WHEN for efficient sorting updates.
- Added IsFollowingBatch and IsBlockedBatch methods in UserRepository for batch checking follow and block relationships, optimizing performance.
This commit is contained in:
lafay
2026-03-26 01:50:54 +08:00
parent 56bd971e42
commit 7b41dfeb00
9 changed files with 386 additions and 109 deletions

View File

@@ -255,46 +255,49 @@ func (r *CommentRepository) GetReplies(parentID string) ([]*model.Comment, error
return comments, err
}
// Like 点赞评论
// Like 点赞评论(使用事务保证数据一致性)
func (r *CommentRepository) Like(commentID, userID string) error {
// 检查是否已经点赞
var existing model.CommentLike
err := r.db.Where("comment_id = ? AND user_id = ?", commentID, userID).First(&existing).Error
if err == nil {
// 已经点赞
return nil
}
if err != gorm.ErrRecordNotFound {
return err
}
return r.db.Transaction(func(tx *gorm.DB) error {
// 检查是否已经点赞
var existing model.CommentLike
err := tx.Where("comment_id = ? AND user_id = ?", commentID, userID).First(&existing).Error
if err == nil {
// 已经点赞
return nil
}
if err != gorm.ErrRecordNotFound {
return err
}
// 创建点赞记录
like := &model.CommentLike{
CommentID: commentID,
UserID: userID,
}
err = r.db.Create(like).Error
if err != nil {
return err
}
// 创建点赞记录
like := &model.CommentLike{
CommentID: commentID,
UserID: userID,
}
if err := tx.Create(like).Error; err != nil {
return err
}
// 增加评论点赞数
return r.db.Model(&model.Comment{}).Where("id = ?", commentID).
UpdateColumn("likes_count", gorm.Expr("likes_count + 1")).Error
// 增加评论点赞数
return tx.Model(&model.Comment{}).Where("id = ?", commentID).
UpdateColumn("likes_count", gorm.Expr("likes_count + 1")).Error
})
}
// Unlike 取消点赞评论
// Unlike 取消点赞评论(使用事务保证数据一致性)
func (r *CommentRepository) Unlike(commentID, userID string) error {
result := r.db.Where("comment_id = ? AND user_id = ?", commentID, userID).Delete(&model.CommentLike{})
if result.Error != nil {
return result.Error
}
if result.RowsAffected > 0 {
// 减少评论点赞数
return r.db.Model(&model.Comment{}).Where("id = ?", commentID).
UpdateColumn("likes_count", gorm.Expr("likes_count - 1")).Error
}
return nil
return r.db.Transaction(func(tx *gorm.DB) error {
result := tx.Where("comment_id = ? AND user_id = ?", commentID, userID).Delete(&model.CommentLike{})
if result.Error != nil {
return result.Error
}
if result.RowsAffected > 0 {
// 减少评论点赞数
return tx.Model(&model.Comment{}).Where("id = ?", commentID).
UpdateColumn("likes_count", gorm.Expr("likes_count - 1")).Error
}
return nil
})
}
// IsLiked 检查是否已点赞
@@ -304,6 +307,33 @@ func (r *CommentRepository) IsLiked(commentID, userID string) bool {
return count > 0
}
// IsLikedBatch 批量检查是否点赞(解决 N+1 问题)
// 返回 map[commentID]bool
func (r *CommentRepository) IsLikedBatch(commentIDs []string, userID string) map[string]bool {
result := make(map[string]bool)
if len(commentIDs) == 0 || userID == "" {
return result
}
// 初始化所有 commentID 为 false
for _, commentID := range commentIDs {
result[commentID] = false
}
// 一次性查询所有点赞记录
var likedCommentIDs []string
r.db.Model(&model.CommentLike{}).
Where("comment_id IN ? AND user_id = ?", commentIDs, userID).
Pluck("comment_id", &likedCommentIDs)
// 更新已点赞的评论
for _, commentID := range likedCommentIDs {
result[commentID] = true
}
return result
}
// AdminCommentListFilter 管理端评论列表筛选条件
type AdminCommentListFilter struct {
Keyword string
@@ -367,17 +397,58 @@ func (r *CommentRepository) GetAdminCommentByID(id string) (*model.Comment, erro
return &comment, nil
}
// BatchDelete 批量删除评论
// BatchDelete 批量删除评论(使用单次事务批量删除,避免 N+1 问题)
func (r *CommentRepository) BatchDelete(ids []string) ([]string, error) {
var failedIDs []string
for _, id := range ids {
if err := r.Delete(id); err != nil {
failedIDs = append(failedIDs, id)
}
if len(ids) == 0 {
return nil, nil
}
return failedIDs, nil
// 先查询所有评论获取 post_id 和状态信息
type commentInfo struct {
ID string
PostID string
Status model.CommentStatus
}
var comments []commentInfo
if err := r.db.Model(&model.Comment{}).Where("id IN ?", ids).Scan(&comments).Error; err != nil {
return ids, err
}
err := r.db.Transaction(func(tx *gorm.DB) error {
// 批量删除评论点赞记录
if err := tx.Where("comment_id IN ?", ids).Delete(&model.CommentLike{}).Error; err != nil {
return err
}
// 批量删除评论(软删除)
if err := tx.Where("id IN ?", ids).Delete(&model.Comment{}).Error; err != nil {
return err
}
// 更新帖子的评论数(仅统计已发布评论)
postCountMap := make(map[string]int)
for _, c := range comments {
if c.Status == model.CommentStatusPublished {
postCountMap[c.PostID]++
}
}
for postID, count := range postCountMap {
if err := tx.Model(&model.Post{}).Where("id = ?", postID).
UpdateColumns(map[string]any{
"comments_count": gorm.Expr("comments_count - ?", count),
"updated_at": gorm.Expr("updated_at"),
}).Error; err != nil {
return err
}
}
return nil
})
if err != nil {
return ids, err
}
return nil, nil
}
// GetCommentsByPostIDForAdmin 管理端获取帖子的评论列表(包含所有状态)