You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在DynamoDB中处理点赞(含取消)的并发问题?

DynamoDB处理点赞/取消点赞并发问题的解决方案

核心思路

要解决这个问题,关键是同时跟踪帖子的点赞用户状态和点赞总数,并利用DynamoDB的原子更新+条件表达式机制,确保并发操作的正确性。仅存储upvote总数的设计无法判断用户是否已点赞,必然会出现重复操作导致的数据错误。

表结构调整

基于需求优化后的表结构:

  • 哈希键:post_id(唯一标识帖子)
  • 新增属性:voted_users(String Set类型),存储所有给该帖子点过赞的用户ID

注:无需单独维护upvote属性,点赞数可直接通过voted_users集合的长度计算,避免数据冗余和不一致风险。如果业务需要单独存储upvote,也可在更新集合时同步更新该字段,但推荐用集合长度计算更可靠。

具体操作实现

1. 点赞操作

用户点击点赞按钮时,执行以下逻辑:

  • 前置条件:当前用户ID不在voted_users集合中
  • 原子操作:将用户ID添加到voted_users集合
  • 并发保障:DynamoDB的UpdateItem是原子操作,条件不满足时会抛出ConditionalCheckFailedException,不会执行无效更新

示例代码(Python boto3):

import boto3
from botocore.exceptions import ClientError

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('your_post_table')

def handle_like(post_id, user_id):
    try:
        response = table.update_item(
            Key={'post_id': post_id},
            UpdateExpression='ADD voted_users :user_id',
            ConditionExpression='NOT contains(voted_users, :user_id)',
            ExpressionAttributeValues={':user_id': {user_id}},
            ReturnValues='ALL_NEW'
        )
        upvote_count = len(response['Attributes']['voted_users'])
        return {"status": "success", "upvote": upvote_count, "action": "liked"}
    except ClientError as e:
        if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
            item = table.get_item(Key={'post_id': post_id}).get('Item', {})
            upvote_count = len(item.get('voted_users', set()))
            return {"status": "failed", "upvote": upvote_count, "action": "already_liked"}
        raise

2. 取消点赞操作

用户再次点击按钮(取消点赞)时,执行以下逻辑:

  • 前置条件:当前用户ID在voted_users集合中
  • 原子操作:将用户ID从voted_users集合移除

示例代码:

def handle_unlike(post_id, user_id):
    try:
        response = table.update_item(
            Key={'post_id': post_id},
            UpdateExpression='DELETE voted_users :user_id',
            ConditionExpression='contains(voted_users, :user_id)',
            ExpressionAttributeValues={':user_id': {user_id}},
            ReturnValues='ALL_NEW'
        )
        upvote_count = len(response['Attributes']['voted_users'])
        return {"status": "success", "upvote": upvote_count, "action": "unliked"}
    except ClientError as e:
        if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
            item = table.get_item(Key={'post_id': post_id}).get('Item', {})
            upvote_count = len(item.get('voted_users', set()))
            return {"status": "failed", "upvote": upvote_count, "action": "not_liked"}
        raise

前端配合逻辑

  • 按钮点击前,可通过缓存或查询接口确认当前用户的点赞状态(即voted_users是否包含当前用户ID)
  • 调用对应的点赞/取消点赞接口
  • 根据接口返回的upvote数和action字段更新按钮状态(比如成功点赞后按钮显示"取消点赞",反之显示"点赞")
  • 遇到条件失败的情况(如重复点击点赞),直接同步最新状态即可,无需额外报错提示

并发安全性说明

DynamoDB的UpdateItem是原子性操作,条件表达式在服务器端校验,只有满足条件才会执行更新。即使多个用户同时操作同一帖子,也不会出现:

  • 同一用户重复点赞导致点赞数多次增加
  • 取消未点赞的帖子导致点赞数为负数
  • 点赞数与实际点赞用户数不一致的情况

内容的提问来源于stack exchange,提问作者xoxocoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 00:45:33