GVKun编程网logo

Mybatis-Plus自动填充失效原因和解决方案(mybatisplus自动填充无效)

10

本文将带您了解关于Mybatis-Plus自动填充失效原因和解决方案的新内容,同时我们还将为您解释mybatisplus自动填充无效的相关知识,另外,我们还将为您提供关于MP(MyBatis-Plus

本文将带您了解关于Mybatis-Plus自动填充失效原因和解决方案的新内容,同时我们还将为您解释mybatisplus自动填充无效的相关知识,另外,我们还将为您提供关于MP(MyBatis-Plus)的自动填充功能、mybatis plus CU自动填充 和 软删除自动填充的实现方法、MyBatis Plus 的自动填充功能、Mybatis Plus公共字段自动填充-动力节点的实用信息。

本文目录一览:

Mybatis-Plus自动填充失效原因和解决方案(mybatisplus自动填充无效)

Mybatis-Plus自动填充失效原因和解决方案(mybatisplus自动填充无效)

前言

今天在公司无聊闲来无事,就想找点事做,想起来之前有个服务有个bug,就是Mybatis-Plus在做增删改的时候创建时间和修改时间这些公共的字段没有自动填充,于是我就开始找bug了。。。

问题

从图片中大家可以清楚看到一条sql有4个字段的值是null

正是公共字段:

  • creationDate 创建时间
  • createdBy 创建人
  • lastUpdateDate 更新时间
  • lastUpdateBy 更新人

需要注意的是在触发自动填充之前是要在公共字段中配置枚举类的

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime creationDate;
    
    @TableField(fill = FieldFill.INSERT)
    private String createdBy;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime lastUpdateDate;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String lastUpdateBy;

配置这些什么意思想必没有必要解释了吧,直接看代码注释吧

public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入时填充字段
     */
    INSERT,
    /**
     * 更新时填充字段
     */
    UPDATE,
    /**
     * 插入和更新时填充字段
     */
    INSERT_UPDATE
}

于是我就在Mybatis-Plus在配置自动填充的配置类中开始Debug

@Component
@Slf4j
public class BaseEntityMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject MetaObject) {
        log.info("star fill ..........");
        UserBo user = AuthHolder.currentSysUser();
        String userBy = user.getId();
        this.strictInsertFill(MetaObject, "createdAt", LocalDateTime.class, LocalDateTime.Now());
        this.strictInsertFill(MetaObject, "createdBy", String.class, userBy);
        this.strictInsertFill(MetaObject, "updatedAt", LocalDateTime.class, LocalDateTime.Now());
        this.strictInsertFill(MetaObject, "updatedBy", String.class, userBy);
        this.strictInsertFill(MetaObject, "lastUpdateDate", LocalDateTime.class, LocalDateTime.Now());
        this.strictInsertFill(MetaObject, "lastUpdateBy", String.class, userBy);
        this.strictInsertFill(MetaObject, "creationDate", LocalDateTime.class, LocalDateTime.Now());
    }

    @Override
    public void updateFill(MetaObject MetaObject) {
        UserBo user = AuthHolder.currentSysUser();
        String userBy = user.getId();
        this.strictInsertFill(MetaObject, "updatedAt", LocalDateTime.class, LocalDateTime.Now());
        this.strictInsertFill(MetaObject, "updatedBy", String.class, userBy);
        this.strictInsertFill(MetaObject, "last_update_date", LocalDateTime.class, LocalDateTime.Now());
        this.strictInsertFill(MetaObject, "last_update_by", String.class, userBy);
    }
}

上面代码就是这个服务的自动填充配置,insertFill方法是新增出发填充,updateFill是修改自动填充

虽然加了@Component注解、日志、和断点,但是在Debug的时候发现并没有进入这段自动填充的代码,

大家从上图可以看到Insert语句依旧没有进入方法

解决方法

经过排查发现我的问题是在配置多数据源的地方出现的问题,少了一段红框的代码。

为什么没有进入自动填充的配置类?

答案:通俗点讲就是这边在配置数据源的时候做了局部的处理,把默认的机制给改了,需要手动指定实现MetaObjectHandler的类。

常见失效原因

我的这个问题还是比较难发现的,一般常见的原因如下几种

原创不易,转载请标注来源!

微信公众号:小航学Java

博客园:https://www.cnblogs.com/mrhang/

CSDN:https://blog.csdn.net/weixin_46040901

掘金:https://juejin.cn/user/4156577737093352

专注Java相关技术:SSM、Spring全家桶、微服务、MysqL、MyCat、集群、分布式、中间件、Linux、网络、多线程,偶尔讲点运维Jenkins、Nexus、Docker、ELK,偶尔分享些技术干货,致力于Java全栈开发!

图片

MP(MyBatis-Plus)的自动填充功能

MP(MyBatis-Plus)的自动填充功能

什么是自动填充

有些表中会有更新时间、创建时间、更新人或者创建人这些字段。

每次对数据进行新增、删除、修改时都需要对这些字段进行设置。传统的做法是在进行这些操作前,对Entity的字段进行set设置,然后再进行操作。这种做法不仅容易忘记导致出错、而且代码会显得特别冗余。

虽然新增时间和修改时间可以使用数据库的时间,但是新增人和修改人就不能使用这样的功能。

所以MP就提供自动填充的功能,帮助自定设置这些字段的值,提升开发效率,代码也会显得特别优雅。

使用MP实现自动填充

step1:在Entity上添加注解

// 插入数据时进行自动填充@TableField(fill = FieldFill.INSERT)private Date createTime;// 更新数据时进行自动填充@TableField(fill = FieldFill.UPDATE)private Date updateTime;

step2:编写自动填充实现类

@Configuration@EnableTransactionManagement@MapperScan("com.csx.demo.spring.boot.dao")public class MyBatisPlusConfig { private static final Logger log = LoggerFactory.getLogger(MyBatisPlusConfig.class); // MetaObjectHandler 这接口有很多方法,一般情况.........

mybatis plus CU自动填充 和 软删除自动填充的实现方法

mybatis plus CU自动填充 和 软删除自动填充的实现方法

这篇文章主要介绍了mybatis plus CU自动填充 和 软删除自动填充的实现方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

说明

CU 是 CRUD 中的创建和修改

本文实现以下需求效果

创建数据时自动填充 createTime

更新数据时自动填充 updateTime(每次修改都自动填充新的 updateTime 值)

软删除数据时自动填充 deleteUserId 和 deleteTime

创建

实体类

为实体类(DO)的 createTime 字段配置以下 Annotation,代表标记在插入(insert into)时自动填充字段值

@TableField(fill = FieldFill.INSERT) private Date createTime;

实现 MetaObjectHandler

如果实体(DO)中配置了上面的注解,就会执行这个 handler。这里在 insert 时自动填充 createTime 字段的值

public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { private static final String createTime = "createTime"; @Override public void insertFill(MetaObject MetaObject) { this.strictInsertFill(MetaObject, createTime, Date::new, Date.class); // 关于 is_delete 字段,这里不提供默认值,因为官方推荐设置数据库中列的默认值 } @Override public void updateFill(MetaObject MetaObject) {} }

配置

注入 IOC 容器。

在 MybatisPlusMetaObjectHandler 类上配置 @Configuration 注解也可以达到同样目的。

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusMetaObjectHandler mybatisPlusCommonDateFieldValueFillHandler(){ return new MybatisPlusMetaObjectHandler(); } }

更新

实体类

在实体类(DO)上配置注解

@TableField(fill = FieldFill.UPDATE) private Date updateTime;

实现 MetaObjectHandler

如果实体(DO)中配置了上面的注解,就会执行这个 handler。这里在 update 时自动填充 updateTime 字段的值

特别注意,这里需要重写 strictFillStrategy 方法,因为默认的行为不会按照预期执行(每次更新数据时都更新 updateTime)

public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { private static final String updateTime = "updateTime"; @Override public void insertFill(MetaObject MetaObject) {} @Override public void updateFill(MetaObject MetaObject) { this.strictUpdateFill(MetaObject, updateTime, Date::new, Date.class); } /** * 严格模式填充策略,默认有值不覆盖,如果提供的值为null也不填充 * * @param MetaObject MetaObject Meta object parameter * @param fieldName java bean property name * @param fieldVal java bean property value of supplier * @return this * @since 3.3.0 */ @Override public MetaObjectHandler strictFillStrategy(MetaObject MetaObject, String fieldName, supplier> fieldVal) { // 但当自动填充字段为 updateTime 时,始终更新它 if (fieldName.equals(updateTime)) { Object obj = fieldVal.get(); MetaObject.setValue(fieldName, obj); } else if (MetaObject.getValue(fieldName) == null) { // 这个 if 是源码中的 Object obj = fieldVal.get(); if (Objects.nonNull(obj)) { MetaObject.setValue(fieldName, obj); } } return this; } }

配置

参考创建章节中的配置,如果已经配置了就不需要再配置了

软删除

配置 application.yml

mybatis-plus: global-config: db-config: logic-delete-field: is_delete # 逻辑删除属性名称(为数据库中的字段名称) logic-delete-value: 1 # 代表已删除的值 logic-not-delete-value: 0 # 代表未删除的值

实体类

在实体类(DO)中对以下字段配置注解。

标识 isDelete 字段作为逻辑删除的标识,然后有两个需要自动填充值的字段。

/** * 逻辑删除标识 * * @TableLogic 注解标记逻辑删除属性 */ @TableLogic private Boolean isDelete; @TableField(fill = FieldFill.UPDATE) private Integer deleteUserId; @TableField(fill = FieldFill.UPDATE) private Date deleteTime;

重写 DefaultsqlInjector

如果需要在软删除时自动填充其他字段的值,才需要重写这个 DefaultsqlInjector,否则忽略本小节。

这里配置了逻辑删除时填充其他字段值的 sqlInjector

public class MybatisPlussqlInjector extends DefaultsqlInjector { @Override public List getmethodList(Class> mapperClass) { final List methods = super.getmethodList(mapperClass); methods.add(new LogicDeleteByIdWithFill()); return methods; } }

实现 MetaObjectHandler

由于 mybatis plus 的 @TableField 注解枚举字段 fill 的值没有我们想要的 Delete,所以 Update 和 Delete 实际上都是走的 updateFill 函数,在函数内部我们需要区分出到底是更新还是软删除,才能继续下一步即自动填充不同行为下字段的值

public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { private static final String deleteUserId = "deleteUserId"; private static final String updateTime = "updateTime"; private static final String deleteTime = "deleteTime"; @Override public void insertFill(MetaObject MetaObject) {} @Override public void updateFill(MetaObject MetaObject) { // 有这两个字段并且也已经 deleteUserId 有值(外面必须为实体类设置 deleteUserId 字段的值),deleteTime 外面不给值 if (MetaObject.hasGetter(deleteUserId) && MetaObject.hasGetter(deleteTime) && !ObjectUtil.isNull(MetaObject.getValue(deleteUserId)) && ObjectUtil.isNull(MetaObject.getValue(deleteTime))) { this.strictUpdateFill(MetaObject, deleteUserId, () -> (Integer) MetaObject.getValue(deleteUserId), Integer.class); this.strictUpdateFill(MetaObject, deleteTime, Date::new, Date.class); } else { this.strictUpdateFill(MetaObject, updateTime, Date::new, Date.class); } } /** * 严格模式填充策略,默认有值不覆盖,如果提供的值为null也不填充 * * @param MetaObject MetaObject Meta object parameter * @param fieldName java bean property name * @param fieldVal java bean property value of supplier * @return this * @since 3.3.0 */ @Override public MetaObjectHandler strictFillStrategy(MetaObject MetaObject, String fieldName, supplier> fieldVal) { // 但当自动填充字段为 updateTime 时,始终更新它 if (fieldName.equals(updateTime)) { Object obj = fieldVal.get(); MetaObject.setValue(fieldName, obj); } else if (MetaObject.getValue(fieldName) == null) { // 这个 if 是源码中的 Object obj = fieldVal.get(); if (Objects.nonNull(obj)) { MetaObject.setValue(fieldName, obj); } } return this; } }

配置(注入到 IOC)

我们需要将上面写的 MybatisPlussqlInjector 注入 IOC 容器。

同样的,这两个 Bean 的配置,与在 MybatisPlussqlInjector 和 MybatisPlusMetaObjectHandler 上配置 @Configuration 注解的效果一样。

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlussqlInjector mybatisPlussqlInjector(){ return new MybatisPlussqlInjector(); } @Bean public MybatisPlusMetaObjectHandler mybatisPlusCommonDateFieldValueFillHandler(){ return new MybatisPlusMetaObjectHandler(); } }

创建 MyBaseRepository

我这里将 Mapper 称为 Repository。因为我用到了 MapStruct 库,个人感觉它更适合被称为 Mapper。

我们需要自己定义一个 MyBaseMapper 继承自 BaseMapper(mybatis plus 的),然后添加一个如下的方法签名,必须跟下面示例代码一样,因为我猜测内部是通过反射来调用的这个函数,所以方法签名必须一致,否则无法被 mybatis plus 库调用哦。

public interface MyBaseMapper extends BaseMapper { /** * 逻辑删除填充其他字段的值 * * @param entity 要删除的实体对象 * @return 受影响记录数量 */ int deleteByIdWithFill(Entity entity); }

我们原来的 Repository 继承自 mybatis plus 的 BaseMapper,现在我们需要修改为继承自上面新写的 MyBaseMapper。

创建 MyBaseService

因为我希望 XXXService 中也有 deleteByIdWithFill 函数,所以这里我还自定义了 Service 的基类,如果不需要的话可以忽略本小节。

自定义的 MyBaseService 继承自 mybatis plus 的 IService 接口,然后添加如下方法签名,注意方法签名中的返回值是 boolean 而不是 int,因为写 Service 需要方便外部使用。

public interface MyBaseService extends IService { /** * 逻辑删除填充其他字段的值 * * @param entity 要删除的实体对象 * @return 受影响记录数量 */ boolean deleteByIdWithFill(Entity entity); }

然后我们写一个 MyBaseService 的实现类。

注意这里我们需要继承自 mybatis plus 的 ServiceImpl 实现,减少我们自己实现的代码量,同时还需要实现我们的 MyBaseService 接口,然后内部写的巴巴适适的上一篇:SpringBoot整合jersey的示例代码下一篇:Java 批量删除html中注释内容的方法

热门搜索:

自动填充 

Excel自动填充 

序号自动填充 

自动填充功能 

表单自动填充 

相关文章

mybatis plus CU自动填充 和 软删除自动填充的实现方法

2021-10-18阅读(2701)评论(0)推荐()

这篇文章主要介绍了mybatis plus CU自动填充 和 软删除自动填充的实现方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借...

Mybatis-Plus自动填充的实现示例

2021-09-10阅读(3377)评论(0)推荐()

这篇文章主要介绍了Mybatis-Plus自动填充的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小...

Mybatis plus通用字段自动填充的示例

2021-10-06阅读(10123)评论(0)推荐()

这篇文章主要介绍了Mybatis plus通用字段自动填充的示例,帮助大家更好的理解和使用Mybatis,感兴趣的朋友可以了解下

MyBatis-Plus 修改和添加自动填充时间方式

2021-11-25阅读(8816)评论(0)推荐()

这篇文章主要介绍了MyBatis-Plus 修改和添加自动填充时间方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Mybatis-Plus自动填充更新操作相关字段的实现

2021-10-06阅读(6779)评论(0)推荐()

这篇文章主要介绍了Mybatis-Plus自动填充更新操作相关字段的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

mybatis-plus主键id生成、字段自动填充的实现代码

2021-10-06阅读(8007)评论(0)推荐()

这篇文章主要介绍了mybatis-plus主键id生成、字段自动填充的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可...

MybatisPlus 自动填充的实现

2021-10-06阅读(5472)评论(0)推荐()

这篇文章主要介绍了MybatisPlus 自动填充的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来...

取消

有人回复时邮件通知我

提交评论

MyBatis Plus 的自动填充功能

MyBatis Plus 的自动填充功能

一. 背景

我们的实体类中经常会用到创建时间 (createTime),修改时间 (updateTime) 之类的常用字段,如果每次插入和更新都去手动生成并填充,会产生很多重复的代码,MyBatis Plus其实已经为我们提供了自动填充功能,只要我们进行简单的配置,即可实现代码的简化。

代码采用 SpringBoot 进行开发。

二.实现步骤

整体实现思路:

通过抽取公用字段封装到 BaseEntity 类中,再将使用到此公共字段的类继承基类,最后由 MyBatis Plus 帮我们实现自动填充。

1.在基类 BaseEntity 代码中添加注解,用于标识需要填充的字段:

/**
 * @description 实体基类.
 */

@Data
@ApiModel(value = "BaseEntity", description = "实体基类")
public class BaseEntity implements Serializable {

    private static final long serialVersionUID = 7229711996915758071L;

    /**
     * 主键
     */
    @Id
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键自增列")
    protected Long id;

    /**
     * 创建时间(新增时自动填充创建时间)
     */
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    protected Date createTime;

    /**
     * 更新时间(更新时自动填充更新时间)
     */
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.UPDATE)
    protected Date updateTime;

    /**
     * 是否已删除 0:未删除 1:已删除
     */
    @ApiModelProperty(value = "是否已删除 0:未删除 1:已删除")
    private Integer isDelete = 0;
}

在创建时间 createTime 上添加 @TableField(fill = FieldFill.INSERT) 注解;

在更新时间 updateTime 上添加 @TableField(fill = FieldFill.UPDATE) 注解;

其中的FieldFill有以下几种取值:

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

2.实现用户实体类 User,继承 BaseEntity


/**
 * @description 用户
 */
@Data
@ApiModel(value = "User", description = "用户表")
@TableName("user")
public class User extends BaseEntity {

    /**
     * 用户名
     */
    @Length(min = 4, max = 30, message = "用户名长度为4-30个字符")
    @ApiModelProperty(value = "用户名")
    private String userName;

    /**
     * 密码(加密后)
     */
    @ApiModelProperty(value = "密码")
    private String password;

    /**
     * 用户姓名
     */
    @ApiModelProperty(value = "用户姓名")
    private String realName;

    @Override
    public String toString() {
        return "User[" +
                "id=" + id +
                ",userName='" + userName +
                ",realName='" + realName +
                ",createTime=" + createTime +
                ",updateTime=" + updateTime +
                ']';
    }

}

3.自定义实现类 MyMetaObjectHandler

/**
 * @description: 实现元对象处理器接口,用于实现时间的自动填充
 * @date: 2020/9/7 16:44
 **/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject MetaObject) {
        log.info("start insert fill ....");
        // 这里的 createTime 填写需要生成的字段名称
        setFieldValByName("createTime", new Date(), MetaObject);
    }

    @Override
    public void updateFill(MetaObject MetaObject) {
        log.info("start update fill ....");
        // 这里的 updateTime 填写需要生成的字段名称
        setFieldValByName("updateTime", MetaObject);
    }
}

一定要加上 @Component 进行注入,否则会导致配置不生效;

4.插入数据测试

@RunWith(springrunner.class)
@SpringBoottest
public class UserTest {
  @Autowired
  private UserMapper userMapper;
 
  @Test
  public void testInsert(){
    User user = new User();
    user.setUserName("testInsert");
    user.setRealName("测试插入");
    int result = userMapper.insert(user);
    System.out.println(user);
  } 
}

5.修改数据测试

@Test
public void testUpdate(){
  User user = new User();
  user.setId(2L);
  user.setUserName("testUpdate");
  int result = userMapper.updateById(user);
  System.out.println(user);
}

Mybatis Plus公共字段自动填充-动力节点

Mybatis Plus公共字段自动填充-动力节点

如果你使用了Mybatis Plus,可以借助于其自动填充功能来实现。

基于 Mybatis Plus 3.3.0

只需要实现MetaObjectHandler接口:br/>@Component
public class MybatisAuditHandler implements MetaObjectHandler {
br/>@Override
public void insertFill(MetaObject metaObject) {
// 声明自动填充字段的逻辑。
String userId = AuthHolder.getCurrentUserId();
this.strictInsertFill(metaObject,“creator”,String.class, userId);
this.strictInsertFill(metaObject,“createTime”, LocalDateTime.class,LocalDateTime.now());
}





@Override
public void updateFill(MetaObject metaObject) {
// 声明自动填充字段的逻辑。
String userId = AuthHolder.getCurrentUserId();
this.strictUpdateFill(metaObject,"updater",String.class,userId);
this.strictUpdateFill(metaObject,"updateTime", LocalDateTime.class,LocalDateTime.now());
}





}
然后我们扩展一下Mybatis Plus的Model把公共审计字段放进去并声明对应的填充策略:
public abstract class BaseEntity<T extends Model<?>> extends Model {
@TableField(fill = FieldFill.INSERT)
private String creator;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime addTime;
@TableField(fill = FieldFill.UPDATE)
private String updater;
@TableField(fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
}










最后我们的实体类不再直接继承Model改为上面的BaseEntity:br/>@Data
@EqualsAndHashCode(callSuper = false)
public class UserInfo extends BaseEntity {
@TableId(value = “user_id”, type = IdType.ASSIGN_ID)
private String userId;
private String username;




@Override
protected Serializable pkVal() {
return this.userId;
}
}



这样我们就不用再关心这几个公共字段了,当然你可以根据需要添加更多你需要填充的字段。

今天的关于Mybatis-Plus自动填充失效原因和解决方案mybatisplus自动填充无效的分享已经结束,谢谢您的关注,如果想了解更多关于MP(MyBatis-Plus)的自动填充功能、mybatis plus CU自动填充 和 软删除自动填充的实现方法、MyBatis Plus 的自动填充功能、Mybatis Plus公共字段自动填充-动力节点的相关知识,请在本站进行查询。

本文标签: