甩掉手动赋值!MyBatis-Plus 自动填充实战秘籍

关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言

在数据库设计中,常常有一些字段每次都需要赋值,如创建时间、更新时间、操作人、删除标识等。很多时候,为了赶项目匆匆的赋值了一些业务字段,而漏掉了这些字段,导致查询问题的时候,时间点或者操作人对不上,加大了定位问题的难度。

有没有框架级的技术,全局处理这样的统一字段呢?当然有。

Mybatis-Plus自动填充技术帮我们解决问题。

02 自动填充实现

使用Mybtis-Plus之前,我们需要简单的搭建环境。

2.1 Mybatis-Plus 简单搭建

Maven

xml 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>${mybatis-plus.version}</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

配置

properties 复制代码
# 数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username=root
spring.datasource.password=root

# 日志实现
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 开启驼峰匹配
mybatis-plus.configuration.map-underscore-to-camel-case=true
# 配置全局数据库主键
mybatis-plus.global-config.db-config.id-type=auto

启动类增加Mapper扫描

@MapperScan("com.simonking.boot.mybaits.mapper")

实体

java 复制代码
@Data
@TableName("user_info")
public class UserInfo {
    
    /**
     * 主键ID
     **/
    @TableId
    private Integer id;

    /**
     * 姓名
     **/
    private String name;

    /**
     * 年龄
     **/
    private Integer age;


    /**
     * 性别
     **/
    private String sex;

    /**
     * 工作
     **/
    private String job;

    /**
     * 生日
     **/
    private LocalDateTime birthday;

    /**
     * 创建时间
     **/
    private LocalDateTime createdTime;

    /**
     * 更新时间
     **/
    private LocalDateTime updateTime;
}

继承BaseMapper

java 复制代码
public interface UserInfoMapper extends BaseMapper<UserInfo> {

}

到这里,Mybatis-Plus就搭建好了,可以注解注入xxxMapper调用方法了。

2.2 标记自动填充的字段

在实体类中,你需要使用 @TableField 注解来标记哪些字段需要自动填充,并指定填充的策略。

java 复制代码
@Data
@TableName("user_info")
public class UserInfo {
    
    // 其他字段...

    /**
     * 创建时间
     **/
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createdTime;

    /**
     * 更新时间
     **/
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

FieldFill填充的枚举:

java 复制代码
public enum FieldFill {
    DEFAULT,       // 默认不处理
    INSERT,        // 插入填充字段
    UPDATE,        // 更新填充字段
    INSERT_UPDATE  // 插入和更新填充字段
}

2.3 实现MetaObjectHandler

创建一个类来实现 MetaObjectHandler 接口,并重写 insertFillupdateFill 方法。并确保实现类被Spring管理,可以通过 @Component@Bean 注解来实现。

java 复制代码
@Slf4j
@Component
public class AutoFillMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("insertFill 开始自动填充......");
        this.strictInsertFill(metaObject, "createdTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("updateFill 开始自动填充......");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

2.4 测试

java 复制代码
 @Test
void contextLoads01() {
    UserInfo userInfo = new UserInfo();
    userInfo.setName("test");
    userInfo.setAge(18);
    userInfoMapper.insert(userInfo);
}

从运行结果来看,cteated_timeupdate_time已经被赋值了。

2.5 思考

这种全局的自动填充有什么问题呢?

先看截图:

这里填充的时候,需要指定字段的名称。但是如果因为开发人员定义错字段,如update_time -> updated_time等,这里就需要穷举所有的字段。

有人可能说是开发规范的问题,的确是。但是这种问题确实有点别扭。

能不能通过注解字段指定别名,统一自动赋值的字段呢?官方暂时不支持这种方式。

03 实现原理

自动赋值的的触发机制是如何实现的呢?第一反应,应该是使用了Mybatis的拦截器插件,细看了之后,并不是。我们一起来看看。

Mybatis-Plus自动填充调用MetaObjectHandler,涉及了两个的类:

  • com.baomidou.mybatisplus.core.MybatisParameterHandler

3.1 MybatisParameterHandler

com.baomidou.mybatisplus.core.MybatisParameterHandler是对Mybaits原生的org.apache.ibatis.scripting.defaults.DefaultParameterHandler的增强。DefaultParameterHandlerMybatis处理SQL参数的核心类,负责:

  • Java 对象转换为 JDBC 参数
  • 设置 PreparedStatement 的参数值
  • 处理类型转换器(TypeHandler

MybatisParameterHandler自然也就具备了这些功能。构造函数的功能:

我们从源码中可以看到,在创建MybatisParameterHandler对象的时候,就会根据sqlCommandType执行insertFill()还是updateFill()

3.2 实例化

我们来看看org.apache.ibatis.executor.parameter.ParameterHandler是怎么实例化的:

04 小结

上面就是Mybatis-Plus自动填充的实现和源码分析,下一期,我们将自己通过拦截器或者注解的方式,实现属于我们自己的自动填充的功能。

相关推荐
Warren9836 分钟前
Java Stream流的使用
java·开发语言·windows·spring boot·后端·python·硬件工程
程序视点2 小时前
IObit Uninstaller Pro专业卸载,免激活版本,卸载清理注册表,彻底告别软件残留
前端·windows·后端
xidianhuihui2 小时前
go install报错: should be v0 or v1, not v2问题解决
开发语言·后端·golang
架构师沉默2 小时前
Java优雅使用Spring Boot+MQTT推送与订阅
java·开发语言·spring boot
tuokuac2 小时前
MyBatis 与 Spring Boot版本匹配问题
java·spring boot·mybatis
zhysunny3 小时前
05.原型模式:从影分身术到细胞分裂的编程艺术
java·原型模式
进击的铁甲小宝3 小时前
Django-environ 入门教程
后端·python·django·django-environ
草履虫建模3 小时前
RuoYi-Vue 项目 Docker 容器化部署 + DockerHub 上传全流程
java·前端·javascript·vue.js·spring boot·docker·dockerhub
皮皮林5513 小时前
强烈建议你不要再使用Date类了!!!
java
掘金码甲哥3 小时前
Go动态感知资源变更的技术实践,你指定用过!
后端