MyBatis-Plus 扩展功能

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


逻辑删除

提示:这里可以添加本文要记录的大概内容:

逻辑删除 是一种数据管理策略,通过标记字段(如 is_deleted)标识数据状态,而非物理删除数据。
优势

  • 数据可恢复性
  • 审计追踪能力
  • 避免误删风险

思路

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为 1
  • 查询时只查询标记为 0 的数据

一、配置逻辑删除字段

方式一:全局配置(推荐)

就是在application.yaml文件中配置逻辑删除的字段名称和值即可

application.yml 中配置全局逻辑删除规则:

yaml 复制代码
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDeleted  # 逻辑删除字段名(实体类字段名)
      logic-delete-value: 1         # 删除标记值
      logic-not-delete-value: 0     # 未删除标记值

方式二:实体类注解配置

在实体类字段上使用 @TableLogic 注解:

java 复制代码
@Data
public class User {
    @TableLogic
    private Integer isDeleted; // 逻辑删除字段(默认值:0未删除,1已删除)
}

优先级:注解配置 > 全局配置。


二、逻辑删除流程

  • 删除操作 :自动将 DELETE 语句转换为 UPDATE,设置 is_deleted = 1
  • 查询操作 :自动附加 WHERE is_deleted = 0 过滤条件

三、完整代码示例

1. 实体类定义

java 复制代码
@Data
@TableName("tb_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String username;
    private Integer balance;
    
    @TableField("is_deleted") // 启用逻辑删除
    private Integer isDeleted; 
}

2. Mapper 接口

java 复制代码
public interface UserMapper extends BaseMapper<User> {
    // 无需手动编写删除方法
}

3. SQL语句

sql 复制代码
//删除操作
UPDATE user SET is_deleted = 1 WHERE id = 1 AND is_deleted = 0;

// 查询操作
SELECT * FROM user WHERE is_deleted = 0;

四、高级配置

1. 自定义逻辑删除字段

若数据库字段名或值不符合默认配置,可通过注解指定:

java 复制代码
@TableLogic(value = "0", delval = "1") // 未删除=0,已删除=1
private Integer status; 

2. 排除非逻辑删除字段

若某实体不需要逻辑删除功能:

java 复制代码
public class Order {
    @TableField(exist = false)
    private Integer isDeleted; // 忽略逻辑删除字段
}

枚举处理

一、枚举处理场景

将数据库字段与 Java 枚举类型自动映射,常见场景:

  • 状态标识:订单状态(0待支付、1已支付、2已取消)
  • 类型分类:用户类型(ADMIN 管理员、USER 普通用户)
  • 多语言处理:国际化状态码映射

二、核心实现方案

方案 1:使用 @EnumValue 注解(推荐)

实现原理

通过注解标记枚举中与数据库字段对应的属性,MyBatis-Plus 自动完成值转换。

步骤 1:定义枚举类
java 复制代码
public enum UserStatus {
    NORMAL(1, "正常"),
    FROZEN(2, "冻结");

    @EnumValue  // 标记数据库存储的值
    private final int code;
    private final String desc;

    UserStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }
}
步骤 2:实体类中使用枚举
java 复制代码
@Data
@TableName("tb_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String username;
    
    private UserStatus status; // 直接使用枚举类型
}
步骤 3:全局配置(可选)

application.yml 中指定枚举处理策略:

yaml 复制代码
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

方案 2:实现 IEnum 接口

适用场景:需要更灵活的控制或兼容旧代码。

定义枚举类
java 复制代码
public enum UserType implements IEnum<Integer> {
    ADMIN(1),
    USER(2);

    private final int code;

    UserType(int code) {
        this.code = code;
    }

    @Override
    public Integer getValue() { // 定义数据库存储的值
        return this.code;
    }
}
实体类使用
java 复制代码
public class User {
    private UserType userType; // 自动映射
}

三、高级用法

1. 自定义枚举处理器

场景:需要将枚举转换为 JSON 字符串存储。

步骤 1:实现 TypeHandler
java 复制代码
@MappedTypes(UserStatus.class)
public class JsonEnumTypeHandler extends BaseTypeHandler<UserStatus> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, 
                                  UserStatus parameter, JdbcType jdbcType) {
        ps.setString(i, objectMapper.writeValueAsString(parameter));
    }

    // 其他方法实现类似...
}
步骤 2:局部注解配置
java 复制代码
public class User {
    @TableField(typeHandler = JsonEnumTypeHandler.class)
    private UserStatus status;
}

2. 多字段枚举映射

场景:需要同时存储枚举编码和描述。

实体类设计
java 复制代码
public class Order {
    private Integer statusCode;  // 存储枚举 code
    private String statusName; 

    // 业务方法获取枚举
    public OrderStatus getStatus() {
        return OrderStatus.of(this.statusCode);
    }
}

四、完整示例测试

1. 插入数据

java 复制代码
@Test
void testInsert() {
    User user = new User();
    user.setUsername("test");
    user.setStatus(UserStatus.FROZEN); // 设置枚举值
    userMapper.insert(user);
}

生成 SQL

sql 复制代码
INSERT INTO tb_user (username, status) VALUES ('test', 2)

2. 查询数据

java 复制代码
@Test
void testSelect() {
    User user = userMapper.selectById(1L);
    System.out.println(user.getStatus()); // 输出: FROZEN
}

生成 SQL

sql 复制代码
SELECT id,username,status FROM tb_user WHERE id=1

五、最佳实践

方案 适用场景 优点
@EnumValue 注解 新项目开发 配置简洁,代码直观
IEnum 接口实现 需要兼容旧枚举定义 无侵入性改造
自定义 TypeHandler 复杂存储格式(如JSON) 高度灵活,可定制化

统一规范建议

  1. 所有业务枚举统一使用 @EnumValue 注解
  2. 数据库字段名与枚举类名保持语义一致(如 order_status 对应 OrderStatus
  3. 禁止直接使用 ordinal() 作为存储值(易导致值混乱)

六、常见问题

问题 1:枚举字段查询失效

现象 :使用 QueryWrapper 查询时无法识别枚举值
解决方案

java 复制代码
wrapper.eq(User::getStatus, UserStatus.NORMAL); // 直接传入枚举对象

问题 2:数据库存枚举名称

需求 :存储 NORMAL 而非数字编码
配置

java 复制代码
public enum UserStatus {
    @EnumValue
    NORMAL, FROZEN // 默认存储 name()
}

通过合理运用 MyBatis-Plus 的枚举处理机制,可以实现数据库字段与 Java 枚举类型的优雅映射,提升代码可读性和健壮性。

相关推荐
曼岛_17 分钟前
Windows系统Python多版本运行解决TensorFlow安装问题(附详细图文)
windows·python·tensorflow
仙人掌_lz20 分钟前
如何在本地使用Ollama运行 Hugging Face 模型
java·人工智能·servlet·ai·大模型·llm·ollama
大神薯条老师30 分钟前
Python高级爬虫之JS逆向+安卓逆向1.4节:数据运算
爬虫·python·机器学习·数据分析·网络爬虫
学也不会30 分钟前
ocr-不动产权识别
java·linux·ocr
喵手39 分钟前
Java 反射:动态代理,你真了解它吗?
java·后端·java ee
jackson凌40 分钟前
【Java学习笔记】Java第一课,梦开始的地方!!!
java·笔记
倚栏听风雨41 分钟前
IDEA插件 - 静态代码语法检查
java
雷渊42 分钟前
在RocketMQ中,既然普通消息类型可以通过key来路由到指定队列中实现顺序消息,为什么还需要顺序消息这个类型呢?
java·后端·面试
水w1 小时前
【Python爬虫】简单介绍2
开发语言·爬虫·python·beautifulsoup
程序员小假1 小时前
如何使用Java开发在线生成 pdf 文档 ?
java·后端