Mybatis-Plus

介绍

MyBatis-Plus 是一个 MyBatis 的增强工具,它在 MyBatis 的基础上只做增强不做改变,旨在简化开发流程和提高开发效率。它具备以下特性:

  • 无侵入性:MyBatis-Plus 仅作为增强,不会对现有工程产生影响。
  • 性能损耗小:自动注入基本的 CURD 操作,对性能的影响微乎其微。
  • 强大的 CRUD 支持:内置了通用的 Mapper 和 Service,通过少量配置即可实现单表的大部分 CRUD 操作。
  • Lambda 表达式支持:方便地编写查询条件,减少字段错误的可能性。
  • 主键自动生成:支持多种主键策略,包括分布式唯一 ID 生成器。
  • ActiveRecord 模式支持:通过继承 Model 类,实体类可以直接进行 CRUD 操作。
  • 自定义全局操作支持:允许全局通用方法的注入。
  • 内置代码生成器:可以快速生成 Mapper、Model、Service、Controller 层代码。
  • 内置分页插件:基于 MyBatis 物理分页,简化分页查询的实现。
  • 多数据库支持:支持包括 MySQL、Oracle、PostgreSQL 等在内的多种数据库。
  • 性能分析插件:能够输出 SQL 语句及其执行时间,帮助优化慢查询。
  • 全局拦截插件:提供操作智能分析阻断,预防误操作。

MyBatis-Plus 适用于需要简化数据库操作并提高开发效率的场景,尤其适合企业级应用开发。

使用

引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

继承接口

实体类

实体类(POJO,Plain Old Java Object)通常不需要继承特定的接口,它们应该只是简单的 JavaBeans,具有属性和对应的 getter 和 setter 方法。MyBatis-Plus 通过注解来识别和处理实体类与数据库表之间的映射关系。不过,如果你想利用 MyBatis-Plus 提供的 ActiveRecord 特性,实体类可以继承 com.baomidou.mybatisplus.extension.activerecord.Model 接口。这样,实体类就可以直接使用 MyBatis-Plus 提供的一系列数据库操作方法,例如插入、更新、删除和查询等。

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;

import java.io.Serializable;

@Data
@TableName("user") // 指定表名
public class User extends Model<User> implements Serializable {
    private Long id;
    private String name;
    private Integer age;
}

MybatisPlus根据PO实体的信息来推断出表的信息,从而生成SQL的。默认情况下:

  • MybatisPlus会把PO实体的类名驼峰转下划线作为表名
  • MybatisPlus会把PO实体的所有变量名驼峰转下划线作为表的字段名,并根据变量类型推断字段类型
  • MybatisPlus会把名为id的字段作为主键

但很多情况下,默认的实现与实际场景不符,因此MybatisPlus提供了一些注解便于我们声明表信息。

@TableName

@TableNmae:表名注解,标识实体类对应的表。

@TableName("user")
public class User {
    private Long id;
    private String name;
}

TableName

属性类型必须指定默认值描述
valueString“”表名
schemaString“”schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMapString“”xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludePropertyString[]{}需要排除的属性名 @since 3.3.1
@TableId

@TableId:主键注解,标识实体类中的主键字段

@TableName("user")
public class User {
   @TableId
   private Long id;
   private String name;
}

TableId

属性类型必须指定默认值描述
valueString“”表名
typeEnumIdType.NONE指定主键类型

IdType

描述
AUTO数据库 ID 自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert 前自行 set 主键值
ASSIGN_ID分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)

这里比较常见的有三种:

  • AUTO:利用数据库的id自增长
  • INPUT:手动生成id
  • ASSIGN_ID:雪花算法生成Long类型的全局唯一id,这是默认的ID策略
@TableField

@TableField:普通字段注解

@TableName("user")
public class User {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    @TableField("isMarried")
    private Boolean isMarried;
    @TableField("concat")
    private String concat;
}

一般情况下我们并不需要给字段添加@TableField注解,一些特殊情况除外:

  • 成员变量名与数据库字段名不一致
  • 成员变量是以isXXX命名,按照JavaBean的规范,MybatisPlus识别字段时会把is去除,这就导致与数据库不符。
  • 成员变量名与数据库一致,但是与数据库的关键字冲突。使用@TableField注解给字段名添加转义字符:` `

TableField

属性类型必须指定默认值描述
valueString“”数据库字段名
existbooleantrue是否为数据库表字段
conditionString“”字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s}
updateString“”字段 update set 部分注入,例如:当在version字段上注解update=“%s+1” 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)
typeHandlerTypeHander类型处理器 (该默认值不代表会按照该值生效)
numericScaleString“”指定小数点后保留的位数

Mapper

在使用 MyBatis-Plus 时,Mapper 接口通常需要继承 com.baomidou.mybatisplus.core.mapper.BaseMapper 接口。BaseMapper 提供了一系列基础的 CRUD 操作方法,这样在实现 Mapper 接口时,你无需自己编写这些基本操作方法的实现。

例如,如果你有一个 User 实体类,你可以创建一个对应的 Mapper 接口如下:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.model.User;

public interface UserMapper extends BaseMapper<User> {
    // 这里可以添加一些自定义的方法
}

在这个例子中,UserMapper 接口继承了 BaseMapper 接口,并且指定了 User 作为泛型参数。这样,UserMapper 接口就自动拥有了 MyBatis-Plus 提供的所有基本 CRUD 操作,包括但不限于:

  • insert(T entity):插入一条记录。
  • deleteById(Serializable id):根据 ID 删除记录。
  • updateById(T entity):根据 ID 更新记录。
  • selectById(Serializable id):根据 ID 查询记录。
  • selectList(Wrapper<T> queryWrapper):根据条件构造器查询列表。

通过继承 BaseMapper,你可以极大地简化数据访问层的代码,同时利用 MyBatis-Plus 提供的扩展功能,比如条件构造器、分页插件等。如果需要额外的自定义数据库操作方法,也可以在 Mapper 接口中添加自定义方法,并在对应的 Mapper XML 文件或使用 MyBatis-Plus 的注解方式提供实现。

Service层

在 MyBatis-Plus 中,Service 层通常不需要继承特定的接口,因为 MyBatis-Plus 已经通过 Mapper 接口提供了基本的 CRUD 功能。Service 层的主要作用是业务逻辑的处理,你可以自由地添加自己的方法来实现业务需求。

然而,MyBatis-Plus 提供了一个 IService 接口,它可以作为一个服务层的基础接口,提供一些通用的业务操作方法。如果你想要利用 MyBatis-Plus 的一些内置服务功能,你可以让你的服务类实现这个接口。IService 接口提供了一些方法,比如批量保存、根据条件查询等,但这些方法通常在实际开发中使用较少,因为业务逻辑往往需要更定制化的方法。

例如,你可以这样定义一个服务接口:

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.model.User;

public interface UserService extends IService<User> {
    // 在这里添加你的业务方法
}

在对应的ServiceImpl实现这个服务接口:

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import com.example.demo.service.UserService;

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    // 实现业务方法
    @Override
    public void someBusinessMethod() {
        // 业务逻辑代码
    }
}

在这个例子中,UserServiceImpl 继承了 MyBatis-Plus 提供的 ServiceImpl 类,并实现了 UserService 接口。ServiceImpl 类已经实现了 IService 接口,因此你可以直接使用它提供的所有方法,同时也可以在 UserServiceImpl 中添加自定义的业务方法。

总的来说,Service 层的设计取决于你的业务需求,MyBatis-Plus 提供的 IService 和 ServiceImpl 主要是为了提供便利和扩展性,但不是强制性要求。

插件

在使用MybatisPlus以后,基础的Mapper、Service、PO代码相对固定,重复编写也比较麻烦。因此MybatisPlus官方提供了代码生成器根据数据库表结构生成PO、Mapper、Service等相关代码。只不过代码生成器同样要编码使用,也很麻烦。MybatisPlus的插件,它可以基于图形化界面完成MybatisPlus的代码生成,非常简单。
在这里插入图片描述
首先需要配置数据库地址,在Idea顶部菜单中,找到Tools,选择Config Database:
在这里插入图片描述
在弹出的窗口中填写数据库连接的基本信息:
在这里插入图片描述
点击OK保存。
然后再次点击Idea顶部菜单中的other,然后选择Code Generator,在弹出的表单中填写信息:
在这里插入图片描述

JSON类型处理器

对于数据库表中为JSON类型的字段,要读取该字段的属性时就非常不方便。如果要方便获取,在定义实体类POJO的该字段时最好是一个Map或者实体类。而一旦我们把这个字段改为对象类型,就需要在写入数据库时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。

具体做法是在实体类上加上一个@TableName(autoResultMap = true)注解,在对应的字段上加上@TableField(typeHandler = ListLongTypeHandler.class)

package com.itheima.mp.domain.po;

import lombok.Data;

@Data
@TableName(value = "UserInfo ", autoResultMap = true)
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
    @TableField(typeHandler = ListLongTypeHandler.class)
    private OtherInfo otherInfo;
}

分页

配置分页插件

在未引入分页插件的情况下,MybatisPlus是不支持分页功能的,IService和BaseMapper中的分页方法都无法正常起效。
所以,我们必须配置分页插件。

package com.itheima.mp.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 初始化核心插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

使用

分页查询,将mybatis-plus的IPage对象作为Controller的入参,导致前端swagger接口文档显示很多不需要的入参的问题。
在这里插入图片描述
可以先写一个通用分页入参的基类

@Data
@ApiModel(description = "基础分页入参")
public class BasePageReq {

    @ApiModelProperty(value = "当前页")
    @NotNull
    private Integer current;

    @ApiModelProperty(value = "每页行数")
    @NotNull
    @Range(min = 1, max = 999)
    private Integer size;
}

然后自己的分页业务业务入惨继承这个基类

@Data
public class MenuPermissionPageRequest extends BasePageReq {

    @ApiModelProperty(value = "租户id", hidden = true)
    private Long tenantId;

    @ApiModelProperty(value = "菜单名称")
    private String searchMenuName;

    @ApiModelProperty(value = "权限名称")
    private String searchPermissionName;

    @ApiModelProperty(value = "权限编码")
    private String searchPermissionCode;

}

将这个类定义作为Controller入参

@GetMapping("page/list")
@ApiOperation("分页查询菜单操作权限列表(关键字搜索)")
public Result<IPage<MenuPermissionInfoResponse>> getPermissionPageList(@Valid MenuPermissionPageRequest req) {
    IPage<MenuPermissionInfoResponse> pageList = menuPermissionFacade.getMenuPermissionPageList(req);
    return Result.ok(pageList);
}

查询的时候重新构造mybatis-plus的IPage对象作为Dao层的分页查询的入参。

public IPage<MenuPermissionInfoResponse> getMenuPermissionPageList(MenuPermissionPageRequest req) {
    Long tenantId = 2L;
    req.setTenantId(tenantId);
    IPage<MenuPermissionInfoResponse> page = new Page<>(req.getCurrent(), req.getSize());
    List<MenuPermissionInfoResponse> list = menuPermissionService.getMenuPermissionPageList(page, req);
    page.setRecords(list);
    return page;
}

分页查询中,对于返回值实体类如何方便的转换到VO给前端

可以通过ipage的convert的方法,方便的转化记录的类型。

@Override
public IPage<GroupApplyPermissionVO> listGroupApplyPermission(GroupApplyPermissionPageReq req) {
    Long schoolId = BizContext.getUser().getSchoolId();
    IPage<ApplyAuth> page = new Page<>(req.getCurrent(), req.getSize());
    LambdaQueryChainWrapper<ApplyAuth> wrapper = this.lambdaQuery().eq(ApplyAuth::getSchoolId, schoolId);
    wrapper.orderByDesc(ApplyAuth::getCreatedOn);
    wrapper.page(page);
    return page.convert(e -> {
        GroupApplyPermissionVO groupApplyPermissionVO = new GroupApplyPermissionVO();
        groupApplyPermissionVO.setAuthId(e.getId())
                .setStuId(e.getKidId())
                .setStuName(e.getKidName())
                .setUserId(e.getUserId())
                .setUserName(e.getUserName())
                .setClazzId(e.getClazzId())
                .setClazzName(e.getClazzName());
        return groupApplyPermissionVO;
    });
}

一个问题:修改人和修改时间的自动填充问题

update不带实体类, 是无法触发字段填充,以下代码在更新时,框架不会自动填充修改人和修改时间

return activityService.lambdaUpdate()
.eq(Activity::getId, id)
.set(Activity::getIsCancelled, Boolean.TRUE)
.update();

以上代码输出以下sql

UPDATE
    sc_menu_permission 
SET
    is_deleted=true 
WHERE
    is_deleted=0 
    AND (
        tenant_id = 2 
        AND id IN (
            178
        )
    );

解决方法:构建一个空的实体类作为update方法的参数

@Override
public void deleteMenuPermissionByTenantIdAndIds(Long tenantId, List<Long> permissionIds) {
    super.lambdaUpdate()
            .eq(MenuPermission::getTenantId, tenantId)
            .in(MenuPermission::getId, permissionIds)
            .set(MenuPermission::getIsDeleted, Boolean.TRUE)
            .update(new MenuPermission());
}

以上代码输出以下sql

UPDATE
    sc_menu_permission 
SET
    modified_by=0,
    modified_on=2022-06-16T21:07:54.988,
    is_deleted=true 
WHERE
    is_deleted=0 
    AND (
        tenant_id = 2 
        AND id IN (
            178
        )
    );
  • 28
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mybatis-plusMyBatis增强工具包,用于简化CRUD操作。该工具包为MyBatis提供了一些高效,有用,即用的功能,使用它可以有效地节省您的开发时间。Mybatis-plus特征与MyBatis完全兼容 启动时自动配置 开箱即用的用于操作数据库的界面 强大而灵活的条件包装器 生成主键的多种策略 Lambda样式的API 全能和高度可定制的代码生成器 自动分页操作 SQL注入防御 支持活动记录 支持可插拔的自定义界面 内置许多有用的扩展Mybatis-plus功能1、单表CURD(简单 + 批量)操作,自动完成(支持 like 比较等查询)。 2、分页插件,Count查询自动或自定义SQL查询。 3、Spring根据不同环境加载不同配置支持(支持typeAliasesPackage通配符扫描)。 【自动生成Entity Mapper Service文件】Mybatis-plusMybatis增强工具包) v3.3.2更新日志分页参数提取,单元测试用例修复 达梦数据库代码生成器表过滤支持 微软数据库代码生成器表过滤支持 修复代码生成器属性字段规则错误 SelectById 支持自定义方法名 修复分页插件获取数据库类型问题 Json转换器空值处理 bugfix(mybatis-plus-generator):SQL类型返回错误问题 调整未知方言异常,自动识别url转换小写匹配. fix: 初始化TableInfo中遇到多个字段有@TableId注解时未能抛出异常的问题 SuperController有Class参数的set方法 增加方法StrategyConfig.setSuperServiceImplClass(java.lang.Class<?>). 代码生成器命名策略调整. 扩展分页缓存key值计算. 去除方法推测,直接访问属性字段. 修正枚举处理器类型不匹配比较. 修改表前缀匹配方式 修改在Mybatis全局配置文件中设置分页插件参数不生效问题 修改在Mybatis全局配置文件中设置分页插件参数不生效问 修复PR未指定解析器的时候引发空指针 增加分页插件limit参数配置 修复指定superEntityClass重复生成父类字段问题 无主键的情况无需导入IdType与TableId包 调整生成BaseResultMap格式 支持lombok模式下选择是否进行链式set生成 修复解析器for update错误 过滤PG约束列(只留下主键约束) 增加生成器禁用模板生成 fix(kotlin): 修复动态表名BUG,最大努力替换表名 修复PG约束生成重复属性字段问题 fix(kotlin): 将LambdaUtils中缓存的key改为String 代码生成器增加数据库关键字处理接口 fix github/issues/2454 支持注解可继承 新增 AES 加密数据库用户名密码 优化方法入参泛型,支持更多类型 修复代码生成器开启移除is前缀生成实体缺少包导入 fixed github issues/2470Mybatis-plus截图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值