目录
数据库信息依旧采用MyBatis-Plus详解Ⅰ(请点击这里跳转查看)里的数据信息,在此基础上进行这一节的讲解。
一、@TableName
经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在 Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表
由此得出结论, MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决 定,且默认操作的表名和实体类型的类名一致。
如果不一致,会发生什么?现在就测试一下,将数据库中的"user"表改成"t_user",再随机运行一个测试的方法,看看会报什么错。

解决1:通过@TableName解决问题
现在我们可以通过在实体类上使用@TableName注解而不更改数据库信息来解决这个问题。
解决2:通过全局配置解决问题
在开发的过程中,我们经常遇到以上的问题,即实体类所对应的表都有固定的前缀,例如t_或tbl_
此时,可以使用MyBatis-Plus提供的全局配置,为实体类所对应的表名设置默认的前缀,那么就 不需要在每个实体类上通过@TableName标识实体类对应的表。
在配置文件中配置如下(.yml):
mybatis-plus:
global-config:
db-config:
table-prefix: t_
# 配置MyBatis-Plus操作表的默认前缀
或是在.properties文件中:
mybatis-plus.global-config.db-config.table-prefix=t_
通过配置文件,就可以免除在实体类中添加@TableName注解了,但是注意这种方式的使用前提:实体类所对应的表都有固定的前缀(并且在 MyBatis-Plus 中,table-prefix 配置只能设置一个统一的前缀,而不能同时设置多个前缀)。
二、@TableId
经过以上的测试, MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认基于雪花算法的策略生成id。
同时问题就来了,若实体类和表中表示主键的不是id,而是其他字段,例如uid , MyBatis-Plus会自动识别uid为主键列吗?
我们实体类中的属性id改为uid,将表中的字段id也改为uid,测试添加功能。
当然,结果肯定是报错的,因为它默认去自增id项,结果发现根本没有id字段,而且实体类中只有uid,它并无法识别uid。

如果我们不想修改数据库去解决这个问题,同样可以通过修改Java后端解决。
解决1:通过@TableId解决问题
在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句,如下:
@TableId的value属性
若实体类中主键对应的属性为id,而表中表示主键的字段为uid,此时若只在属性id上添加注解 @TableId,则抛出异常Unknown column'id'in'field list',即MyBatis-Plus仍然会将id作为表的主键操作,而表中表示主键的是字段uid
此时需要通过@TableId注解的value属性(遇见这种数据库和实体类名称不一致时,只设置一个@TableId就不够用了),指定表中的主键字段
@TableId("uid")或@TableId(value="uid")
@TableId的type属性
type属性用来定义主键策略。
常用的主键策略:
| 值 | 描述 |
|---|---|
|
| 基于雪花算法(Snowflake)生成主键值。这种策略生成的是一个 64 位的长整型(long)主键,具有全局唯一性。它与数据库的自增策略无关,即使数据库的 id 字段没有设置为自增,也可以使用这种策略。这是 MyBatis-Plus 的默认主键策略。 |
IdType.AUTO | 使用数据库的自增策略。这种策略要求数据库的 id 字段必须设置为自增。如果数据库的 id 字段没有设置为自增,使用这种策略会导致插入失败。 |
IdType.INPUT | 由用户手动输入主键值。这种策略不会自动生成主键值,需要在插入数据时显式指定主键值。 |
IdType.NONE | 等同于 IdType.INPUT,由用户手动输入主键值。这种策略不会自动生成主键值,需要在插入数据时显式指定主键值。 |
IdType.ASSIGN_UUID | 基于 UUID 生成主键值。这种策略生成的是一个 32 位的字符串(去除了 - 的 UUID)。它与数据库的自增策略无关,即使数据库的 id 字段没有设置为自增,也可以使用这种策略。 |
示例1 在实体类使用注解
这是我现在的数据库

现在去运行它:

再去查看数据库:
示例2 使用配置文件
首先将实体类方才的注解注释掉,再在配置文件上配置:

重新去运行测试类中的测试语句,查看数据库:
使用配置注解相较于在实体类上添加注解,可以覆盖所有的实体类而不用逐个编写实体类。
三、数据规模增长(含雪花算法)
讲了这么多,mybatis-plus中的默认的雪花算法究竟是什么呢?当然,雪花算法只是应对数据规模增长策略中的其中一个,所以在讲雪花算法之前,还是有必要说一说其他几类。
背景
在项目开发中,需要选择合适的方案去应对数据规模的增长,以应对逐渐增长的访问压力和数据量。
数据库的扩展方式主要包括:业务分库、主从复制,数据库分表。
| 扩展方式 | 描述 |
|---|---|
| 业务分库 | 将不同业务的数据分散存储到不同的数据库服务器,提高系统扩展性和性能。 |
| 主从复制 | 提高系统的读取性能,通过主从复制实现数据的备份和读写分离。 |
| 数据库分表 | 将数据分散到多个表中,应对单表数据量过大导致的性能瓶颈。 |
数据库分表策略
| 分表类型 | 描述 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 垂直分表 | 将表中某些不常用且占大量空间的列拆分到其他表中,以提高查询性能。 | 字段使用频率差异大,某些字段占用空间大 | 提高查询性能 | 增加表的复杂性 |
| 水平分表 | 将表中的行数据分散到多个表中,适用于表行数特别大的情况。 | 单表行数过大,性能瓶颈 | 分布更均匀,扩展性强 | 扩充新表复杂,数据重分布 |
主键生成策略
| 策略类型 | 描述 | 实现方式 | 优点 | 缺点 |
|---|---|---|---|---|
| 主键自增 | 使用数据库的自增策略生成主键。 | 数据库内置功能 | 实现简单,性能高 | 单表限制,不适用于分布式 |
| 分段策略 | 将主键 ID 按照一定范围分段,例如 1-999999 放到表 1 中。 | 手动分段,动态扩充 | 平滑扩充新表 | 数据分布不均匀 |
| 取模策略 | 用主键 ID 对表的数量取模来确定数据所属的表。 | user_id % 表数量 | 表分布均匀 | 扩充新表复杂,需重分布 |
| 雪花算法 | 分布式主键生成算法,保证全局唯一性和有序性。 | 时间戳 + 机器ID + 序列号 | 全局唯一,有序,高效 | 依赖时间戳,需配置节点ID |
雪花算法
| 特性 | 描述 |
|---|---|
| 长度 | 64 位(一个 long 类型) |
| 符号位 | 1 位,标识正负(通常是 0,表示正数) |
| 时间戳 | 41 位,存储毫秒级时间戳的差值,约等于 69.73 年 |
| 机器 ID | 10 位,其中 5 位是数据中心 ID,5 位是机器 ID,可部署在 1024 个节点上 |
| 序列号 | 12 位,表示每毫秒内的流水号,每个节点每毫秒可以生成 4096 个 ID |
| 优点 | 整体上按照时间自增排序,全局唯一,效率高 |
| 缺点 | 依赖时间戳,节点 ID 需要配置,可能出现时间回拨问题 |
四、@TableField
经过以上的测试,我们可以发现, MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和 表中的字段名一致
如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?
情况1
若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格.
例如:实体类属性userName,表中字段user_name
此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
情况2
若实体类中的属性和表中的字段不满足情况1
例如:实体类属性name ,表中字段username
此时需要在实体类属性上使用@TableField("username")设置属性所对应的字段名
假设我的数据库字段名是username,但是对我的实体类属性却写了name,我不想修改,怎么办?就可以加上这么一行注解。
五、@TableLogic
物理删除&逻辑删除
| 概念 | 描述 | 使用场景 |
|---|---|---|
| 物理删除 | 真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据。 | 数据不再需要,彻底删除 |
| 逻辑删除 | 假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍能看到此条数据记录。 | 数据需要保留,可能需要恢复 |
实现逻辑删除
Step 1:数据库中创建逻辑删除状态列
-
在数据库表中添加一个逻辑删除状态列,通常命名为
is_deleted或deleted。 -
设置默认值为
0,表示数据未被删除。
示例 SQL:
ALTER TABLE t_user ADD COLUMN is_deleted TINYINT DEFAULT 0;
Step 2:实体类中添加逻辑删除属性
-
在实体类中添加逻辑删除属性,并使用 MyBatis-Plus 的
@TableLogic注解标记该字段。 -
@TableLogic注解会告诉 MyBatis-Plus,这个字段用于逻辑删除。
示例实体类:
package com.example.mybatisplus.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@TableName("t_user")
public class User {
private Long id;
private String username;
private String name;
private Integer age;
private String email;
@TableLogic
private Integer isDeleted; // 逻辑删除字段
}
Step 3:测试逻辑删除功能
-
测试删除功能:调用删除方法时,MyBatis-Plus 会将
is_deleted字段的值更新为1,而不是物理删除数据。 -
测试查询功能:默认情况下,查询操作会自动过滤掉
is_deleted为1的数据。
示例测试代码:
import com.example.mybatisplus.entity.User;
import com.example.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class LogicDeleteTest {
@Autowired
private UserMapper userMapper;
@Test
public void testLogicDelete() {
// 插入一条测试数据
User user = new User();
user.setUsername("testUser");
user.setName("Test User");
user.setAge(25);
user.setEmail("test@example.com");
userMapper.insert(user);
// 执行逻辑删除
userMapper.deleteById(user.getId());
// 查询被逻辑删除的数据
User deletedUser = userMapper.selectById(user.getId());
assert deletedUser == null; // 默认查询不会返回逻辑删除的数据
// 查询所有数据,包括逻辑删除的数据
List<User> allUsers = userMapper.selectList(null);
assert allUsers.size() == 1; // 包括逻辑删除的数据
}
}
SQL 语句示例
-
逻辑删除操作:
UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0; -
查询操作:
SELECT id, username AS name, age, email, is_deleted FROM t_user WHERE is_deleted=0;
1104

被折叠的 条评论
为什么被折叠?



