MyBatis-Plus 实战避坑指南
2025/7/20后端开发#Java#MyBatis-plus
MyBatis-Plus 实战避坑指南
前言
想象这样一个场景:你优雅地编写了 MyBatis-Plus 的 MetaObjectHandler,创建、更新操作的公共字段处理得井井有条。然而在某个风和日丽的下午,当你执行 removeById 相关操作时,却发现数据竟然真的被删除了?这是怎么回事?
逻辑删除的配置
在 MyBatis-Plus 中,逻辑删除是一个非常实用的功能。它可以让我们在删除数据时不真正删除记录,而是通过修改某个字段的值来标记数据为已删除状态。
1. 添加逻辑删除字段
首先,我们需要在数据库表中添加一个逻辑删除字段,通常命名为 deleted 或 is_deleted:
ALTER TABLE user ADD COLUMN deleted TINYINT(1) DEFAULT 0 COMMENT '逻辑删除标识(0-未删除,1-已删除)';
2. 实体类配置
在实体类中添加对应的字段,并使用 @TableLogic 注解:
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String email;
@TableLogic
private Integer deleted;
// 其他字段...
}
3. 全局配置
在 application.yml 中配置逻辑删除的全局设置:
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
常见问题与解决方案
问题1:逻辑删除不生效
现象:调用 removeById() 方法后,数据被物理删除而不是逻辑删除。
原因:
- 实体类中没有添加
@TableLogic注解 - 全局配置不正确
- 数据库表中没有对应的逻辑删除字段
解决方案:
- 确保实体类字段添加了
@TableLogic注解 - 检查全局配置是否正确
- 验证数据库表结构
问题2:查询时包含已删除数据
现象:查询结果中包含了逻辑删除的数据。
原因:
- 查询时使用了原生 SQL
- 自定义的 Mapper 方法没有考虑逻辑删除
解决方案:
// 错误的做法
@Select("SELECT * FROM user WHERE username = #{username}")
User selectByUsername(String username);
// 正确的做法
@Select("SELECT * FROM user WHERE username = #{username} AND deleted = 0")
User selectByUsername(String username);
// 或者使用 MyBatis-Plus 提供的方法
User user = userMapper.selectOne(
new QueryWrapper<User>().eq("username", username)
);
最佳实践
1. 统一的基础实体类
创建一个基础实体类,包含公共字段:
@Data
public abstract class BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
}
2. 自动填充处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
3. 自定义删除方法
有时候我们需要真正的物理删除,可以自定义方法:
public interface UserMapper extends BaseMapper<User> {
@Delete("DELETE FROM user WHERE id = #{id}")
int deleteByIdPhysically(Long id);
@Update("UPDATE user SET deleted = 1, update_time = NOW() WHERE id = #{id}")
int deleteByIdLogically(Long id);
}
总结
MyBatis-Plus 的逻辑删除功能虽然强大,但在使用过程中需要注意配置的完整性和一致性。通过合理的配置和规范的使用,可以大大提高开发效率,同时保证数据的安全性。
记住以下几个要点:
- 实体类字段必须添加
@TableLogic注解 - 全局配置要正确设置
- 自定义 SQL 要考虑逻辑删除条件
- 建立统一的基础实体类和自动填充机制
希望这篇文章能帮助你在使用 MyBatis-Plus 时避免一些常见的坑!