前面已经介绍了Mybatis-plus基本用法,今天为大家分享一些Mybatis-plus高级应用

  1. 逻辑删除
  2. 自动注入
  3. 枚举类型处理
  4. 多租户

表结构

CREATE TABLE `sys_role` (  `id` varchar(64) NOT NULL COMMENT '主键',  `code` varchar(64) NOT NULL DEFAULT '' COMMENT '角色编码',  `name` varchar(64) NOT NULL DEFAULT '' COMMENT '角色名',  `type` char(2) NOT NULL COMMENT '角色类型,1:管理员,2:普通',  `tenant_code` varchar(64) NOT NULL DEFAULT '' COMMENT '租户编码',  `create_user` varchar(64) NOT NULL DEFAULT '' COMMENT '创建用户',  `create_time` datetime NOT NULL COMMENT '创建时间',  `update_user` varchar(64) NOT NULL DEFAULT '' COMMENT '更新用户',  `update_time` datetime NOT NULL COMMENT '更新时间',  `is_del` char(1) NOT NULL DEFAULT '0' COMMENT '是否删除,0:未删除,1:删除',  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色';




mysql把枚举转换为中文 mybatisplus 枚举类型转化_sql


逻辑删除

全局配置

在配置文件中增加如下配置

mybatis-plus:  global-config:    db-config:      logic-delete-field: isDel#全局逻辑删除字段值 3.3.0开始支持,详情看下面。      logic-delete-value: 1 # 逻辑已删除值(默认为 1)      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

局部配置

在实体类删除字段上增加@TableLogic注解

/** 是否删除,0:未删除,1:删除 */@TableLogicprivate String isDel;

全局配置和局部配置实现的结果是一样的,下面针对局部配置做一下测试

@Autowiredprivate RoleMapper roleMapper;@Testpublic void logicDel() {    roleMapper.deleteById("1");}


mysql把枚举转换为中文 mybatisplus 枚举类型转化_mysql把枚举转换为中文_02


从结果可以看出角色id为1数据的is_del被设置为1

使用Mybatis-plus自带方法删除、更新和查找都会where条件后面加上删除字段

以查询为例看一下效果

@Test void loginDel2() {    roleMapper.selectList(null);}


mysql把枚举转换为中文 mybatisplus 枚举类型转化_字段_03


从打印的sql中可以看出,在where后面添加了is_del='0'限定,所以要查询所有数据可以采用自定义sql实现

自动填充

在项目开发中,表中经常会定义一些公共的字段,例如:修改人,创建人。这时候我们可以采用 MyBatis-Plus 中

的字段自动填充功能去实现。

  1. 在实体类属性上增加@TableField(fill = FieldFill.INSERT_UPDATE)注解,如下所示
@Data@TableName("sys_role")public class Role {    /** 创建人 */    @TableField(fill = FieldFill.INSERT)    private String createUser;    /** 创建时间 */    @TableField(fill = FieldFill.INSERT)    private Date createTime;    /** 更新人 */    @TableField(fill = FieldFill.INSERT_UPDATE)    private String updateUser;    /** 更新时间 */    @TableField(fill = FieldFill.INSERT_UPDATE)    private Date updateTime;    /** 是否删除,0:未删除,1:删除 */    @TableLogic    private String isDel;}

TableField默认有四个

  • DEFAULT:默认不处理
  • INSERT:插入时填充字段
  • UPDATE:更新时填充字段
  • INSERT_UPDATE:插入和更新时填充字段
  1. 定义处理器
@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler {   public static String CREATEUSER_NAMEINBEAN = "createUser";    public static String CREATETIME_NAMEINBEAN = "createTime";    public static String UPDATEUSER_NAMEINBEAN = "updateUser";    public static String UPDATETIME_NAMEINBEAN = "updateTime";    @Override    public void insertFill(MetaObject metaObject) {        boolean createUser = metaObject.hasSetter(CREATEUSER_NAMEINBEAN);        if (createUser) {            this.strictInsertFill(metaObject, CREATEUSER_NAMEINBEAN, String.class, "admin");        }        boolean createTime = metaObject.hasSetter(CREATETIME_NAMEINBEAN);        if (createTime) {            this.strictInsertFill(metaObject, CREATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now());        }        boolean updateUser = metaObject.hasSetter(UPDATEUSER_NAMEINBEAN);        if (updateUser) {            this.strictInsertFill(metaObject, UPDATEUSER_NAMEINBEAN, String.class, "admin");        }        boolean updateTime = metaObject.hasSetter(UPDATETIME_NAMEINBEAN);        if (updateTime) {            this.strictInsertFill(metaObject, UPDATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now());        }    }    @Override    public void updateFill(MetaObject metaObject) {        boolean updateUser = metaObject.hasSetter(UPDATEUSER_NAMEINBEAN);        if (updateUser) {            this.strictInsertFill(metaObject, UPDATEUSER_NAMEINBEAN, String.class, "amdin");        }        boolean updateTime = metaObject.hasSetter(UPDATETIME_NAMEINBEAN);        if (updateTime) {            this.strictInsertFill(metaObject, UPDATETIME_NAMEINBEAN, LocalDateTime.class, LocalDateTime.now());        }    }}
  1. 测试
@Testvoid update() {    // 更新id为2角色的名字为测试2    Role role = new Role();    role.setName("测试2");    role.setId("2");    roleMapper.updateById(role);}


mysql把枚举转换为中文 mybatisplus 枚举类型转化_ide_04


在执行更新操作时自动加上更新人和更新时间

枚举类型处理器

自mybatis3.1.0开始,如果你无需使用原生枚举,可配置默认枚举来省略扫描通用枚举配置 默认枚举配置

  1. 定义枚举类,主要有两种方式

方法一:采用继承IEnum实现

@Getter@AllArgsConstructorpublic enum RoleType implements IEnum {    ADMIN("1"),    COMMON("2");    private String type;    @Override    public Serializable getValue() {        return type;    }}

方法二:注解方式,在枚举类需要解析的属性上增加@EnumValue注解

@Getter@AllArgsConstructorpublic enum RoleType {    ADMIN("1"),    COMMON("2"); @EnumValue//标记数据库存的值是type    private String type;}
  1. 定义实体类
@Data@TableName("sys_role")public class Role { /** 角色类型 */    private RoleType type;}
  1. 配置扫描的枚举包路径
mybatis-plus:  typeEnumsPackage: com.yanyu.spring.mybatisplus.enums


mysql把枚举转换为中文 mybatisplus 枚举类型转化_sql_05


从结果可以看出查询出的角色类型自动转换成了枚举ADMIN

当Mybatis-plus自带的原生方法不能满足我们的需求,我们可以利用器自定义sql

实现步骤:

  1. 创建自定义的类
public class DeleteByCodeMethod extends AbstractMethod {    @Override    public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) {        // 执行的slq        String sql = "delete from "+ tableInfo.getTableName() +" where code = #{code}";        // Mapper接口方法名        String method = "deleteByCode";        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);        return addDeleteMappedStatement(mapperClass, method, sqlSource);    }}
  1. 创建注入器
@Componentpublic class MySqlInject extends DefaultSqlInjector {    @Override    public List getMethodList(Class> mapperClass) {        List methodList = super.getMethodList(mapperClass);        methodList.add(new DeleteByCodeMethod());        return methodList;    }}
  1. 在Mapper中加入自定义方法
public interface RoleMapper extends BaseMapper {    int deleteByCode(@Param("code") String code);}
  1. 测试
@Testvoid deleteByCode() {    // 删除编码为code的角色    roleMapper.deleteByCode("test");}


mysql把枚举转换为中文 mybatisplus 枚举类型转化_枚举类型用法_06


从结果看,我们自定义的根据编码删除数据执行成功

Mybatis-plus官方为我们提供了三种自定义类

  • InsertBatchSomeColumn:批量新增数据,自选字段insert
  • AlwaysUpdateSomeColumnById:根据id更新固定字段
  • LogicDeleteByIdWithFill:根据id逻辑删除,并带字段填充功能

以InsertBatchSomeColumn为例,简单的演示一下怎么使用

  1. 在注入器中加入InsertBatchSomeColumn自定义类
@Componentpublic class MySqlInject extends DefaultSqlInjector {    @Override    public List getMethodList(Class> mapperClass) {        List methodList = super.getMethodList(mapperClass);        methodList.add(new DeleteByCodeMethod());        /**         * 不是逻辑删除的字段包括在内         */        methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete()));        return methodList;    }}
  1. 在Mapper中加入自定义方法
public interface RoleMapper extends BaseMapper {    int insertBatchSomeColumn(List list);}
  1. 测试
@Testvoid insertBatchSomeColumn() {    // 测试批量插入角色1和角色2    Role role1 = new Role();    role1.setCode("ROLE_1");    role1.setName("角色1");    role1.setType(RoleType.ADMIN);    Role role2 = new Role();    role2.setCode("ROLE_2");    role2.setName("角色2");    role2.setType(RoleType.ADMIN);    List roles = new ArrayList<>(Arrays.asList(role1,role2));    roleMapper.insertBatchSomeColumn(roles);}


mysql把枚举转换为中文 mybatisplus 枚举类型转化_枚举类型用法_07


多租户

租户实现

Mybatis-plus多租户依赖于分页插件,下面我们将简单介绍如何实现租户解析

  1. 定义租户解析器
@Beanpublic PaginationInterceptor paginationInterceptor() throws IOException {    PaginationInterceptor paginationInterceptor = new PaginationInterceptor();    TenantSqlParser tenantSqlParser = new TenantSqlParser();    tenantSqlParser.setTenantHandler(new TenantHandler() {        @Override        public Expression getTenantId(boolean select) {            return new StringValue("00000");        }        @Override        public String getTenantIdColumn() {            return "tenant_code";        }        @Override        public boolean doTableFilter(String tableName) {            /**             * 是否加租户信息,false->加,true->不加             */            return false;        }    });    paginationInterceptor.setSqlParserList(Arrays.asList(tenantSqlParser));    return paginationInterceptor;}
  1. 测试
@Testpublic void tenant() {    // 查询id为1的角色    roleMapper.selectById("1");}


mysql把枚举转换为中文 mybatisplus 枚举类型转化_mysql把枚举转换为中文_08


从结果看,sql执行时在查询条件中自动为我们加上了租户判断

特定sql过滤

在开发中有的方法不需要限定租户标识,实现方式有两种

  1. 方式一:通过在分页插件中自定义过滤器,具体实现如下所示
@Beanpublic PaginationInterceptor paginationInterceptor() throws IOException {    PaginationInterceptor paginationInterceptor = new PaginationInterceptor();    TenantSqlParser tenantSqlParser = new TenantSqlParser();    tenantSqlParser.setTenantHandler(new TenantHandler() {        @Override        public Expression getTenantId(boolean select) {            return new StringValue("00000");        }        @Override        public String getTenantIdColumn() {            return "tenant_code";        }        @Override        public boolean doTableFilter(String tableName) {            /**             * 是否加租户信息,false->加,true->不加             */            return false;        }    });    paginationInterceptor.setSqlParserList(Arrays.asList(tenantSqlParser));    paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {        /**         * true 不增加,false 增加         * @param metaObject         * @return         */        @Override        public boolean doFilter(MetaObject metaObject) {            MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);            if("具体方法".equals(ms.getId())) {                return true;            }            return false;        }    });    return paginationInterceptor;}
  1. 方式二:在不需要限定租户的方法上加入
public interface RoleMapper extends BaseMapper {    @SqlParser(filter = true)    int getByCode(String code);}