面试场景题:设计微信朋友圈后端-从接口到数据库的实现

设计微信朋友圈后端:从接口到数据库的实现

微信朋友圈是一个典型的社交应用场景,涉及动态发布、查看、点赞、评论等功能,同时需要支持高并发和权限控制。在这篇博客中,我将从需求分析开始,逐步设计朋友圈的后端接口和数据库结构,并提供基于 Spring Boot 和 MySQL 的 Java 实现代码。


需求分析

微信朋友圈的核心功能包括:

  1. 发布动态:用户可以发布文字、图片、视频等内容。
  2. 查看动态:用户可以查看自己和好友的动态,按时间倒序排列。
  3. 评论与点赞:支持对动态进行评论和点赞。
  4. 权限控制:支持公开、仅好友可见、部分好友可见等设置。
  5. 高并发:需要支持大量用户同时操作。

基于这些需求,后端设计需要满足高并发、低延迟、可扩展性和数据一致性。


接口设计

以下是基于 RESTful 风格的核心 API 设计,使用 JSON 格式交互。

1. 发布动态

  • 接口POST /api/moments

  • 请求参数

    json 复制代码
    {
      "userId": "12345",
      "content": "今天天气很好",
      "media": [
        {"type": "image", "url": "http://example.com/img1.jpg"}
      ],
      "visibility": "friends",
      "visibleUserIds": ["67890"]
    }
  • 响应

    json 复制代码
    {
      "momentId": "10001",
      "createdAt": "2025-03-28T10:00:00Z"
    }

2. 获取朋友圈动态

  • 接口GET /api/moments?userId={userId}&page={page}&size={size}

  • 响应

    json 复制代码
    [
      {
        "momentId": "10001",
        "userId": "12345",
        "username": "张三",
        "content": "今天天气很好",
        "media": [{"type": "image", "url": "http://example.com/img1.jpg"}],
        "createdAt": "2025-03-28T10:00:00Z",
        "likes": 5,
        "comments": [
          {"userId": "67890", "username": "李四", "content": "确实不错"}
        ]
      }
    ]

3. 点赞动态

  • 接口POST /api/moments/{momentId}/like

  • 请求参数

    json 复制代码
    {
      "userId": "67890"
    }
  • 响应

    json 复制代码
    {
      "success": true,
      "likeCount": 6
    }

4. 评论动态

  • 接口POST /api/moments/{momentId}/comment

  • 请求参数

    json 复制代码
    {
      "userId": "67890",
      "content": "确实不错"
    }
  • 响应

    json 复制代码
    {
      "commentId": "20001",
      "createdAt": "2025-03-28T10:05:00Z"
    }

数据库设计

我选择 MySQL 作为主数据库,结合 Redis 优化高并发场景。以下是表结构设计:

表结构

用户表 (users)
sql 复制代码
CREATE TABLE users (
    user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
动态表 (moments)
sql 复制代码
CREATE TABLE moments (
    moment_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    content TEXT,
    media JSON,
    visibility ENUM('public', 'friends', 'private', 'custom') DEFAULT 'friends',
    visible_user_ids JSON,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    like_count INT DEFAULT 0,
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    INDEX idx_created_at (created_at)
);
点赞表 (moment_likes)
sql 复制代码
CREATE TABLE moment_likes (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    moment_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (moment_id) REFERENCES moments(moment_id),
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    UNIQUE INDEX idx_moment_user (moment_id, user_id)
);
评论表 (moment_comments)
sql 复制代码
CREATE TABLE moment_comments (
    comment_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    moment_id BIGINT NOT NULL,
    user_id BIGINT NOT NULL,
    content TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (moment_id) REFERENCES moments(moment_id),
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    INDEX idx_moment_created (moment_id, created_at)
);

优化措施

  • 索引:为动态表添加时间索引,点赞表添加唯一索引防止重复点赞。
  • 分库分表 :按 user_idmoment_id 分片,支持水平扩展。
  • 缓存 :使用 Redis 存储热门动态的 like_count 和时间线数据。

Java 代码实现

以下是基于 Spring Boot 和 MyBatis 的实现,覆盖核心功能。

1. 依赖配置 (pom.xml)

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

2. 实体类

java 复制代码
public class Moment {
    private Long momentId;
    private Long userId;
    private String content;
    private String media; // JSON 字符串
    private String visibility;
    private String visibleUserIds; // JSON 字符串
    private Date createdAt;
    private Integer likeCount;
    // Getters and Setters
}

public class MomentLike {
    private Long id;
    private Long momentId;
    private Long userId;
    private Date createdAt;
    // Getters and Setters
}

public class MomentComment {
    private Long commentId;
    private Long momentId;
    private Long userId;
    private String content;
    private Date createdAt;
    // Getters and Setters
}

3. Mapper 接口

java 复制代码
@Mapper
public interface MomentMapper {
    @Insert("INSERT INTO moments(user_id, content, media, visibility, visible_user_ids) " +
            "VALUES(#{userId}, #{content}, #{media}, #{visibility}, #{visibleUserIds})")
    @Options(useGeneratedKeys = true, keyProperty = "momentId")
    void insert(Moment moment);

    @Select("SELECT m.*, u.username FROM moments m JOIN users u ON m.user_id = u.user_id " +
            "WHERE m.created_at <= #{cursor} ORDER BY m.created_at DESC LIMIT #{size}")
    List<Moment> findMomentsByCursor(@Param("cursor") Date cursor, @Param("size") int size);
}

@Mapper
public interface MomentLikeMapper {
    @Insert("INSERT INTO moment_likes(moment_id, user_id) VALUES(#{momentId}, #{userId})")
    void insert(MomentLike like);

    @Update("UPDATE moments SET like_count = like_count + 1 WHERE moment_id = #{momentId}")
    void incrementLikeCount(Long momentId);
}

@Mapper
public interface MomentCommentMapper {
    @Insert("INSERT INTO moment_comments(moment_id, user_id, content) " +
            "VALUES(#{momentId}, #{userId}, #{content})")
    @Options(useGeneratedKeys = true, keyProperty = "commentId")
    void insert(MomentComment comment);
}

4. Service 层

java 复制代码
@Service
public class MomentService {
    @Autowired
    private MomentMapper momentMapper;
    @Autowired
    private MomentLikeMapper likeMapper;
    @Autowired
    private MomentCommentMapper commentMapper;

    @Transactional
    public Long createMoment(Moment moment) {
        momentMapper.insert(moment);
        return moment.getMomentId();
    }

    public List<Moment> getMoments(Long userId, int page, int size) {
        Date cursor = new Date();
        return momentMapper.findMomentsByCursor(cursor, size);
    }

    @Transactional
    public void likeMoment(Long momentId, Long userId) {
        MomentLike like = new MomentLike();
        like.setMomentId(momentId);
        like.setUserId(userId);
        likeMapper.insert(like);
        likeMapper.incrementLikeCount(momentId);
    }

    @Transactional
    public Long commentMoment(Long momentId, Long userId, String content) {
        MomentComment comment = new MomentComment();
        comment.setMomentId(momentId);
        comment.setUserId(userId);
        comment.setContent(content);
        commentMapper.insert(comment);
        return comment.getCommentId();
    }
}

5. Controller 层

java 复制代码
@RestController
@RequestMapping("/api/moments")
public class MomentController {
    @Autowired
    private MomentService momentService;

    @PostMapping
    public ResponseEntity<Map<String, Object>> createMoment(@RequestBody Moment moment) {
        Long momentId = momentService.createMoment(moment);
        Map<String, Object> response = new HashMap<>();
        response.put("momentId", momentId);
        response.put("createdAt", new Date());
        return ResponseEntity.ok(response);
    }

    @GetMapping
    public ResponseEntity<List<Moment>> getMoments(
            @RequestParam Long userId,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {
        List<Moment> moments = momentService.getMoments(userId, page, size);
        return ResponseEntity.ok(moments);
    }

    @PostMapping("/{momentId}/like")
    public ResponseEntity<Map<String, Object>> likeMoment(
            @PathVariable Long momentId,
            @RequestBody Map<String, Long> request) {
        Long userId = request.get("userId");
        momentService.likeMoment(momentId, userId);
        Map<String, Object> response = new HashMap<>();
        response.put("success", true);
        return ResponseEntity.ok(response);
    }

    @PostMapping("/{momentId}/comment")
    public ResponseEntity<Map<String, Object>> commentMoment(
            @PathVariable Long momentId,
            @RequestBody MomentComment comment) {
        Long commentId = momentService.commentMoment(momentId, comment.getUserId(), comment.getContent());
        Map<String, Object> response = new HashMap<>();
        response.put("commentId", commentId);
        response.put("createdAt", new Date());
        return ResponseEntity.ok(response);
    }
}

系统架构优化

  1. 高并发
    • 使用消息队列(如 Kafka)异步处理点赞和评论。
    • 动态时间线采用"读扩散"模型,聚合好友动态到 Redis。
  2. 权限控制
    • 在 Service 层校验 visibilityvisible_user_ids
  3. 扩展性
    • 媒体文件存储在分布式文件系统(如 S3),URL 存入数据库。
    • 数据库按 user_id 分库分表。

总结

通过这篇博客,我们从需求出发,设计了微信朋友圈的接口和数据库,并用 Java 实现了核心功能。代码虽然简化(未完全实现权限和缓存),但展示了后端开发的基本思路。实际生产中,还需加入异常处理、分布式锁、缓存一致性等优化。

相关推荐
uhakadotcom20 分钟前
快速构建交互式数据应用:Streamlit入门指南
后端·面试·github
无名之逆1 小时前
hyperlane:Rust HTTP 服务器开发的不二之选
服务器·开发语言·前端·后端·安全·http·rust
机构师1 小时前
<iced><rust><GUI>基于rust的GUI库iced的学习(02):svg图片转png
后端·rust
老赵骑摩托1 小时前
Go语言nil原理深度解析:底层实现与比较规则
开发语言·后端·golang
卑微小文1 小时前
惊!代理 IP 竟成社交媒体营销破局“神助攻”!
后端
程序员爱钓鱼1 小时前
Go 语言邮件发送完全指南:轻松实现邮件通知功能
后端·go·排序算法
Cloud_.1 小时前
Spring Boot整合Redis
java·spring boot·redis·后端·缓存
海狸鼠2 小时前
几行代码实现MCP服务端/客户端(接入DeepSeek)
前端·后端
37手游后端团队2 小时前
10分钟读懂RAG技术
人工智能·后端
Moment2 小时前
岗位急招,算法实习、音乐生成、全栈、flutter 都有,早十晚六 😍😍😍
前端·后端·面试