ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MybatisPlus基础学习之自动填充策略

2021-07-18 23:05:13  阅读:319  来源: 互联网

标签:metaObject 填充 自动 user import mybatis MybatisPlus com


4.MybatisPlus自动填充策略

4.1 为什么要进行自动填充处理?

创建时间修改时间!这些操作一遍都是自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表中gmt_creategmt_modified几乎所有的表都要配置上,而且需要自动化

4.2 实现自动填充

实现自动填充我们可以在数据库级别实现,也可以在代码级别实现

4.2.1 在数据库级别实现

1.在数据表中新增创建时间和修改时间字段

1-1 在user表中增加create_time字段

create_time字段Type类型 选择 “datetime” , Deafault默认值 选择 “current_timestamp”

在这里插入图片描述

1-2 在user表中增加update_time字段

update_time字段Type类型 也选择 “datetime” , Deafault默认值 也选择 “current_timestamp”,和create_time字段相同

在这里插入图片描述

2.设置update_time字段自动更新

2-1 选择根据当前时间戳更新

由于在IDEA中并没有发现更新的选项,所以这里使用NaviCat进行设置,勾选 "update_time"字段下的 “根据当前时间戳更新”

在这里插入图片描述

3-2 查看修改后的user数据表

在这里插入图片描述
我们发现数据表中的create_time和update_time字段按照当前时间进行填充了!

3.修改User实体类

package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {
    //对应数据库中的主键 (UUID, 自增Id)
    /**
     * 这里选择的是ASSIGN_ID(3.3.0版本后的推荐使用的,基于雪花算法)
     * 3.3.0之前的版本推荐使用的是ID_WORKER(全局唯一ID,基于雪花算法)
     */
    @TableId(type = IdType.ASSIGN_ID)
    private String id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
   /* *
      * 由于mybatis-plus会自动开启驼峰命名转换
      * 所以对于数据库字段create_time,
      * 在Java实体类中直接使用CreateTime即可
    */
    private Date createTime; //创建时间
    private Date updateTime; //修改时间
}

4.修改用户测试

package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试更新
    @Test
    public void testUpdate() {
        //获取User对象
        User user = new User();
        //设置修改用户的Id
        user.setId("1405056510844735489");
        //设置用户要修改的信息(修改多个属性)
        user.setName("周杰伦");
        user.setAge(24);
        user.setEmail("zjl123@qq.com");
        //通过Id修改用户,并且返回影响行数
        //注意:虽然updateById是通过Id修改信息,但是参数其实是一个对象!
        int result = userMapper.updateById(user);
        //打印受影响行数
        System.out.println(result);
    }

}

5.查看测试结果

5-1 查看控制台输出

在这里插入图片描述

结果我们发现,预编译处理中,并没有动态拼接修改update_time属性!

那么到底更新时间是否进行了修改呢?我们继续查看修改数据结果

5-2 查看修改数据结果

在这里插入图片描述

结果我们发现update_time更新时间确实进行了修改!说明我们在数据库级别实现的自动填充确实有效!

除了可以在数据库级别实现,当然我们也可以通过Java代码级别来实现

4.2.2 在代码级别实现

1.删除默认值和取消更新

在Navicat中分别将 “create_time”"update_time"字段的默认值设为Null,并取消勾选 “根据当前时间戳更新”

在这里插入图片描述

在这里插入图片描述

2.编写User实体类

由于MybatisPlus中提供了使用 @TableField注解 来实现代码级别的自动填充,所以我们首先查看一下它的相关源码,大致了解一下它的基本实现

2-1 查看@TableField注解源码
package com.baomidou.mybatisplus.annotation;

import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.UnknownTypeHandler;

import java.lang.annotation.*;

/**
 * 表字段标识
 *
 * @author hubin sjy tantan
 * @since 2016-09-09
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableField {
    
    .....
        
    /**
     * 字段自动填充策略
     */
    //我们发现,在@TableField注解中有一个枚举类 FieldFill,并且它默认值是DEFAULT
    FieldFill fill() default FieldFill.DEFAULT;
    
    .....

}

2-2 查看FieldFill枚举类源码
package com.baomidou.mybatisplus.annotation;

/**
 * 字段填充策略枚举类
 *
 * <p>
 * 判断注入的 insert 和 update 的 sql 脚本是否在对应情况下忽略掉字段的 if 标签生成
 * <if test="...">......</if>
 * 判断优先级比 {@link FieldStrategy} 高
 * </p>
 *
 * @author hubin
 * @since 2017-06-27
 */
public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入时填充字段
     */
    INSERT,
    /**
     * 更新时填充字段
     */
    UPDATE,
    /**
     * 插入和更新时填充字段
     */
    INSERT_UPDATE
}

FieldFill字段枚举类四种自动填充处理策略,分别是Default (默认不处理)、Insert (插入时填充)、Update (更新时填充)、Insert_Update (插入和更新时填充)

2-3 修改User实体类

由于要在代码级别实现自动填充,所以要在User实体类的createTime和updateTime字段前使用 @TableField注解来实现

package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {
    //对应数据库中的主键 (UUID, 自增Id)
    /**
     * 这里选择的是ASSIGN_ID(3.3.0版本后的推荐使用的,基于雪花算法)
     * 3.3.0之前的版本推荐使用的是ID_WORKER(全局唯一ID,基于雪花算法)
     */
    @TableId(type = IdType.ASSIGN_ID)
    private String id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
   /* *
      * 由于mybatis-plus会自动开启驼峰命名转换
      * 所以对于数据库字段create_time,
      * 在Java实体类中直接使用CreateTime即可
    */
    /* *
     * 使用@TableField注解,设置字段自动填充策略
     * fill的值为FieldFill.INSERT时,表示插入时填充字段
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime; //创建时间
    /* *
     * 使用@TableField注解,设置字段自动填充策略
     * fill的值为FieldFill.INSERT_UPDATE时,表示插入或者更新时填充字段
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime; //修改时间
}

3.编写处理器处理注解

对于自动填充策略的处理,MybatisPlus还提供了专门的数据源对象处理器,我们只需实现MetaObjectHandler接口便可进行一些填充策略的设置

3-1 查看MetaObjectHandler接口源码
package com.baomidou.mybatisplus.core.handlers;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.reflection.MetaObject;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * 元对象字段填充控制器抽象类,实现公共字段自动写入<p>
 * <p>
 * 所有入参的 MetaObject 必定是 entity 或其子类的 MetaObject
 *
 * @author hubin
 * @since 2016-08-28
 */
public interface MetaObjectHandler {

    /**
     * 是否开启了插入填充
     */
    default boolean openInsertFill() {
        return true;
    }
    
    .....
    
    /**
     * 通用填充
     *
     * @param fieldName  Java实体类的属性名称
     * @param fieldVal   Java实体类的属性值
     * @param metaObject 数据源对象参数
     */
    default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
        if (Objects.nonNull(fieldVal) && metaObject.hasSetter(fieldName)) {
            metaObject.setValue(fieldName, fieldVal);
        }
        return this;
    }
    
    ......
        
    
   /**
     * @param metaObject 数据源对象参数
     * @param fieldName Java实体类的属性名称
     * @param fieldType Java实体类的属性类型
     * @param fieldVal Java实体类的属性值
     * @since 3.3.0
     */
     //严格插入填充
    default <T> MetaObjectHandler strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, Object fieldVal) {
        return strictInsertFill(findTableInfo(metaObject), metaObject, Collections.singletonList(StrictFill.of(fieldName, fieldType, fieldVal)));
    }    
    
    ......
        
   /**
     * @param metaObject 数据源对象参数
     * @param fieldName Java实体类的属性名称
     * @param fieldType Java实体类的属性类型
     * @param fieldVal Java实体类的属性值
     * @since 3.3.0
     */   
     //严格更新填充
   default <T> MetaObjectHandler strictUpdateFill(MetaObject metaObject, String fieldName, Class<T> fieldType, Supplier<T> fieldVal) {
        return strictUpdateFill(findTableInfo(metaObject), metaObject, Collections.singletonList(StrictFill.of(fieldName, fieldType, fieldVal)));
    }
}

通过查看源码,我们发现MetaObjectHandler接口,主要有三个填充策略方法,分别是setFieldValByName (通用填充)、strictInsertFill (严格插入填充)、strictUpdateFill(严格更新填充)

3-2 编写自定义的MyMetaObjectHandler实现类

在自定义实现类中,我们只需实现MetaObjectHandler接口,然后重写 insertFill方法 (插入填充),updateFill方法 (更新填充)和 strictFillStrategy方法(严格填充策略)

package com.kuang.mybatis_plus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

//使用Slf4j注解,设置Slf4j日志输出
@Slf4j
//将MyMetaObjectHandler注册为Spring的IOC容器中的组件
@Component
//自定义实现类MyMetaObjectHandler,实现MetaObjectHandler(数据源对象处理器)接口
public class MyMetaObjectHandler implements MetaObjectHandler {

    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        //打印日志信息
        log.info("start insert fill...");
        //是否开启了插入填充
//        this.openInsertFill();
        /* *
         * setFieldValByName方法有三个参数:
         * String fieldName, Object fieldVal, MetaObject metaObject
         * @param fieldName  Java实体类的属性名称
         * @param fieldVal   Java实体类的属性值
         * @param metaObject 数据源对象参数
         */
        //设置创建时间属性和值
        //3.3.0之前使用setFieldValByName方法
//        this.setFieldValByName("createTime",new Date(),metaObject);
        //3.3.0之后推荐使用strictInsertFill方法
        this.strictInsertFill(metaObject,"createTime", LocalDateTime.class,LocalDateTime.now());
        //设置修改时间属性和值
        //3.3.0之前使用setFieldValByName方法
//        this.setFieldValByName("updateTime",new Date(),metaObject);
        //3.3.0之后推荐使用strictInsertFill方法
        this.strictInsertFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());
    }

    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        //打印日志信息
        log.info("start update fill...");
        //设置修改时间属性和值
        //3.3.0之前使用setFieldValByName方法
//        this.setFieldValByName("updateTime",new Date(),metaObject);
        //3.3.0之后推荐使用strictUpdateFill方法
        this.strictInsertFill(metaObject,"updateTime",LocalDateTime.class,LocalDateTime.now());
    }

     //修改严格填充策略
    //默认策略是:如果属性有值,则不覆盖;如果填充值为null,则不填充
    @Override
    public MetaObjectHandler strictFillStrategy(MetaObject metaObject, String fieldName, Supplier<?> fieldVal) {
        //每次填充,直接使用填充值
        //获取字段值,封装到Object对象中
        Object obj = fieldVal.get();
        //判断值是否为空
        if(Objects.nonNull(obj)) {
            metaObject.setValue(fieldName, obj);
        }
        return this;
    }

}
3-3 修改User实体类属性类

这里还需要将User实体类的createTimeupdateTime字段属性类型修改为LocalDateTime,否则插入数据时无法自动填充创建时间和修改时间

package com.kuang.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Date;

@Data //导入无参构造,set和get方法,以及toString方法等
@AllArgsConstructor //导入有参构造
@NoArgsConstructor //再次导入无参构造,防止被有参构造覆盖掉
public class User {
    //对应数据库中的主键 (UUID, 自增Id)
    /**
     * 这里选择的是ASSIGN_ID(3.3.0版本后的推荐使用的,基于雪花算法)
     * 3.3.0之前的版本推荐使用的是ID_WORKER(全局唯一ID,基于雪花算法)
     */
    @TableId(type = IdType.ASSIGN_ID)
    private String id; //用户编号
    private String name; //用户名
    private Integer age; //年龄
    private String email; //邮箱
   /* *
      * 由于mybatis-plus会自动开启驼峰命名转换
      * 所以对于数据库字段create_time,
      * 在Java实体类中直接使用CreateTime即可
    */
    /* *
     * 使用@TableField注解,设置字段自动填充策略
     * fill的值为FieldFill.INSERT时,表示插入时填充字段
     */
    @TableField(fill = FieldFill.INSERT)
    //将createTime修改为LocalDateTime类型
    private LocalDateTime createTime; //创建时间
    /* *
     * 使用@TableField注解,设置字段自动填充策略
     * fill的值为FieldFill.INSERT_UPDATE时,表示插入或者更新时填充字段
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime; //修改时间
}

设置完了严格填充策略,接下来我们就来编写测试类,查看严格填充策略是否生效!

4.编写插入数据测试类

4-1 编写插入数据测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //继承了BaseMapper,所有的方法都来自父类
    //我们也可以编写自己的扩展方法
    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试插入用户数据
    @Test
    public void testInsert() {
       //获取User对象
       User user = new User();
       //设置用户名和年龄以及邮箱等属性
        //使用ASSign_UUID主键策略
        user.setName("杨宗纬");
        user.setAge(44);
        user.setEmail("yzw123456@qq.com");

        //返回受影响的行数(自动帮我们生成Id)
       int result = userMapper.insert(user);
       //打印受影响行数
        System.out.println(result);
       //打印插入的用户信息
       System.out.println(user);
    }

}
4-2 查看控制台输出

在这里插入图片描述

4-3 查看插入数据结果

在这里插入图片描述

结果插入数据成功,插入和修改时间也自动填充了!

5.编写修改数据测试类

5-1 编写修改数据测试类
package com.kuang.mybatis_plus;

import com.kuang.mybatis_plus.mapper.UserMapper;
import com.kuang.mybatis_plus.pojo.User;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
//扫描mapper接口所在包
@MapperScan("com.kuang.mybatis_plus.mapper")
class MybatisPlusApplicationTests {

    //继承了BaseMapper,所有的方法都来自父类
    //我们也可以编写自己的扩展方法
    //通过类型自动装配UserMapper接口
    @Autowired
    private UserMapper userMapper;

    //测试更新
    @Test
    public void testUpdate() {
        //获取User对象
        User user = new User();
        //设置修改用户的Id
        user.setId("1405056510844735489");
        //设置用户要修改的信息(修改多个属性)
        user.setName("周杰伦");
        user.setAge(26);
        user.setEmail("zjl123456@qq.com");
        //通过Id修改用户,并且返回影响行数
        //注意:虽然updateById是通过Id修改信息,但是参数其实是一个对象!
        int result = userMapper.updateById(user);
        //打印受影响行数
        System.out.println(result);
    }

}
5-2 查看控制台输出

在这里插入图片描述

5-3 查看修改数据结果

在这里插入图片描述

结果修改数据成功,修改时间也自动更新!

到这里,MybatisPlus的自动填充策略的基础学习就结束了,欢迎大家学习和讨论!
参考视频链接:https://www.bilibili.com/video/BV17E411N7KN (B站UP主遇见狂神说的MybatisPlus快速入门)

标签:metaObject,填充,自动,user,import,mybatis,MybatisPlus,com
来源: https://blog.csdn.net/weixin_45301250/article/details/118882989

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有