数据库设计实战¶
设计任务管理系统的两张表: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,数据还在) |
| 不写注解的字段 | 字段名驼峰转下划线(createTime → create_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 业务实现