java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot 装饰器@TableField

SpringBoot 装饰器@TableField原理解析

作者:司南锤

本文解析了MyBatis-Plus的@TableField注解,用于非主键字段与数据库列的映射及行为控制,涵盖自动填充、乐观锁、多租户等企业级功能,提供使用技巧、常见问题及示例代码,感兴趣的朋友跟随小编一起看看吧

1. 开胃菜:一句话认识 @TableField

@TableField 是 MyBatis-Plus 提供的字段级注解,用于非主键字段与数据库列的显式绑定行为控制
记住两个关键字:“非主键”“行为控制”——这是它与 @TableId 的核心差异。

2. 为什么需要它?

场景不用 @TableField 的问题用了 @TableField 的收益
实体字段名与列名不一致默认下划线转驼峰失效显式指定 value="user_name"
实体属性非数据库字段MP 会无脑拼接,SQL 报错exist=false 排除
敏感字段不允许查询查询会返回密码select=false 自动屏蔽
插入/更新时要填充手动 set 易遗漏fill=FieldFill.INSERT 自动填充
乐观锁版本号需要手动判断version=true 一键启用

3. 快速上手:5 个最常用的属性

@Data
@TableName("t_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    // 1. 列名不一致
    @TableField("user_name")
    private String name;
    // 2. 虚拟字段,不持久化
    @TableField(exist = false)
    private String token;
    // 3. 查询时不返回
    @TableField(select = false)
    private String password;
    // 4. 插入自动写入
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    // 5. 更新自动写入
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    // 6. 乐观锁
    @Version
    @TableField("version")
    private Integer version;
}

4. 源码级剖析:MP 如何把注解变成 SQL

4.1 解析入口

TableInfoHelper#initTableInfo → 反射读取所有字段 → 构建 TableFieldInfo 列表。

4.2 SQL 拼接

AbstractSqlInjector 注入通用 CRUD 方法 →
DefaultSqlProviderTableFieldInfo 生成 SQL 片段 →
select=false 的字段被主动剔除,exist=false 的字段直接忽略。

4.3 填充与乐观锁

MetaObjectHandler 接口处理 FieldFill
MybatisPlusInterceptor 内的 OptimisticLockerInnerInterceptor 处理 @Version

5. 企业级高阶玩法

5.1 动态过滤字段 —— 防止数据越权

// 场景:普通用户不能查看薪资字段
@TableField(select = false, condition = "%s != 'admin'")
private BigDecimal salary;

配合 TenantLineInterceptor 可实现动态列级权限

5.2 加密存储 —— 自定义 TypeHandler

@TableField(typeHandler = AesTypeHandler.class)
private String idCard;

插入自动加密,查询自动解密,业务代码零侵入

5.3 多租户隔离 —— 租户字段加索引

@TableField("tenant_id")
@InterceptorIgnore(tenantLine = "true") // 跳过插件,避免死循环
private Long tenantId;

6. 高频踩坑 & 排查清单

现象根因正确姿势
更新时 version 不生效实体里 version 为 null先查后改,或者手动 set
虚拟字段被持久化忘记写 exist=false加上即可
select=false 依然查出手写 SQL 未使用 MP 条件构造器LambdaQueryWrapperSqlSelectInterceptor
填充不生效没实现 MetaObjectHandler@Component 实现接口

7. 和 Spring 注解的“梦幻联动”

@Component
public class MyMetaHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // Spring 容器直接注入
        this.strictInsertFill(metaObject, "createTime", 
                              LocalDateTime.class, LocalDateTime.now());
    }
}

@TableField 负责标记,Spring 负责注入,两者解耦,符合单一职责。

8. 总结:一张脑图记住 @TableField

@TableField
├─ value          映射列名
├─ exist          是否持久化
├─ select         是否参与查询
├─ fill           自动填充策略
├─ update         自定义 set 片段
├─ condition      动态条件
├─ typeHandler    类型转换
└─ keepGlobalFormat 保留全局格式

9. 一键复制即可跑的最小 Demo

GitHub:https://github.com/YOUR_NAME/mp-tablefield-demo
分支:feature/tablefield-demo
包含:加密、乐观锁、多租户、自动填充 4 大示例,Maven 一键启动。

10. 评论区 FAQ 预览(提前回答)

Q1@TableField@Column 有什么区别?
A:后者是 JPA 规范,只在 Hibernate 生效;前者是 MyBatis-Plus 专用,功能更强。

Q2:能否在 Kotlin data class 使用?
A:可以,但字段必须声明为 var,否则无法填充。

Q3:性能会下降吗?
A:解析结果缓存到 TableInfo,运行期零反射,性能损耗 < 1%。

到此这篇关于一文讲透一个 SpringBoot 装饰器 —— @TableField的文章就介绍到这了,更多相关SpringBoot 装饰器@TableField内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文