跳转至

数据库设计实战

设计任务管理系统的两张表:t_user(用户)和 t_task(任务),并理解"实体类 ↔ 数据库表"的映射。

表结构

-- 任务管理系统 建表 SQL(第 27 章)
-- 执行:mysql -u root -p < schema.sql,或在客户端里粘贴运行

CREATE DATABASE IF NOT EXISTS task_manager DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;
USE task_manager;

-- 用户表
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    username    VARCHAR(20)  NOT NULL UNIQUE COMMENT '用户名',
    password    VARCHAR(100) NOT NULL        COMMENT 'BCrypt 哈希',
    create_time DATETIME                      COMMENT '创建时间',
    INDEX idx_username (username)
) COMMENT '用户表';

-- 任务表
DROP TABLE IF EXISTS t_task;
CREATE TABLE t_task (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(100) NOT NULL        COMMENT '标题',
    description VARCHAR(500)                 COMMENT '描述',
    status      TINYINT      DEFAULT 0       COMMENT '0待办 1进行中 2已完成',
    user_id     BIGINT                        COMMENT '归属用户 ID(对应 t_user.id)',
    create_time DATETIME,
    update_time DATETIME,
    deleted     TINYINT      DEFAULT 0       COMMENT '逻辑删除 0正常 1删除',
    INDEX idx_user_status (user_id, status)
) COMMENT '任务表';

实体类 ↔ 表的映射

每个实体类对应一张表,每个字段对应一列。MyBatis-Plus 靠注解映射:

注解 作用
@TableName("t_task") 类对应表 t_task
@TableId(type = AUTO) 主键,数据库自增
@TableLogic 逻辑删除字段(删 = 改 deleted=1,数据还在)
不写注解的字段 字段名驼峰转下划线(createTimecreate_time

任务实体完整代码:

package com.javaglm.task.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;

import java.time.LocalDateTime;

/**
 * 任务实体(第 27 章),对应数据库表 t_task。
 * 一个字段 = 一列。MyBatis-Plus 根据它自动生成 SQL。
 */
@TableName("t_task")
public class Task {

    /** 主键,数据库自增。 */
    @TableId(type = IdType.AUTO)
    private Long id;

    private String title;

    private String description;

    /** 0=待办 1=进行中 2=已完成。 */
    private Integer status;

    /** 归属用户 ID(外键关联 t_user)。 */
    private Long userId;

    private LocalDateTime createTime;

    private LocalDateTime updateTime;

    /** 逻辑删除:0=正常 1=已删除。@TableLogic 让 MyBatis-Plus 查询自动过滤已删除。 */
    @TableLogic
    private Integer deleted;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public LocalDateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }

    public Integer getDeleted() {
        return deleted;
    }

    public void setDeleted(Integer deleted) {
        this.deleted = deleted;
    }
}

设计要点

1. 主键自增 id:每行唯一标识,前端列表的 :key 就用它。

2. user_id 外键关联:任务归属某个用户。查询时 WHERE user_id = 当前用户,实现"各人看各人的任务"。注意我们没用数据库层面的外键约束(性能 + 灵活),靠应用层(Service 里校验归属)保证。

3. 逻辑删除 deleted:删任务不是 DELETE,而是 UPDATE deleted=1@TableLogic 让 MP 查询自动加 WHERE deleted=0,已删除的对应用透明不可见。好处:数据可恢复、可审计。

4. 时间字段 create_time / update_time:记录创建和修改时间,排序、审计用。

跑起来

# 1. 建库建表
mysql -u root -p < code/task-manager/src/main/resources/db/schema.sql

# 2. 改 application.yml 里的 password 为你的 MySQL 密码
# 3. 启动
cd code/task-manager && mvn spring-boot:run

实体设计对照

数据库 Java 实体 类型
BIGINT id Long id 主键
VARCHAR(100) title String title 字符串
TINYINT status Integer status 小整数
DATETIME create_time LocalDateTime createTime 时间

为什么 Java 用包装类型 Long 而不是 long

long 默认值是 0,Long 默认是 null。新建任务时 id 还没有,应该是 null(未设置),不是 0。所以主键、可空字段用包装类型。


:octicons-arrow-left-16: 上一章:MyBatis-Plus 数据访问 | 下一章:任务 CRUD 业务实现