MybatisPlus介绍与使用

什么是MybatisPlus

MybatisPlus官网MyBatis-Plus 🚀 为简化开发而生 (baomidou.com)

MyBatis-Plus是MyBatis的一个强大的增强工具包,用于简化开发。该工具包为MyBatis提供了一些高效、有用、开箱即用的功能,使用它可以有效地节省您的开发时间。

开始

一、添加依赖

Mybaits官方提供了starter,集成了Mybatis和MybatisPlus的所有功能,并且实现了自动装配效果,

项目中只需引入MybatisPlus依赖即可

Maven

Springboot2

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

Springboot3

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
  <version>Latest Version</version>
</dependency>

MybaitsPlus只做增强不做改变,引入不会对现有工程造成影响,简单配置即可实现对单表的CURD操作,节省大量时间

二、继承BaseMapper接口

泛型指定对应的实体类型

public interface UserMapper extends BaseMapper<User> {

}

BaseMapper中定义了增删改查方法

三、使用

userMapper.insert(user);

userMapper.deleteById(5L);

改        只会修改填入的字段

User user = new User();
user.setId(5L);
user.setBalance(20000);
//只修改填入的字段
userMapper.updateById(user);

执行的sql语句

UPDATE user SET balance = ? WHERE id = ?

User user = userMapper.selectById(5L);

批量操作,使用对应的Batch方法即可

List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));

常用注解配置

@TableName

该注解用于指定实体类对应的数据库表名。当实体类名与数据库表名不一致,或者实体类名不是数据库表名的驼峰写法时,您需要使用这个注解来明确指定表名。

@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

value

类型: String
默认值: ""

指定实体类对应的数据库表名。如果实体类名与表名不一致,使用这个属性来指定正确的表名。

resultMap

类型: String
默认值: ""

指定在 XML 中定义的 ResultMap 的 ID,用于将查询结果映射到特定类型的实体类对象。

resultMap的认识可以去看这位大佬的文章

浅谈MyBatis中的resultMap(个人总结)_mybatis resultmap 泛型-CSDN博客

autoResultMap

类型: boolean
默认值: false

是否自动构建 resultMap。如果已经设置了 resultMap,这个属性不会生效。

excludeProperty

类型: String[]
默认值: {}
添加于: @since 3.3.1

指定在映射时需要排除的属性名。这些属性将不会被包含在生成的 SQL 语句中。

@TableId

该注解用于标记实体类中的主键字段。如果你的主键字段名为 id,你可以省略这个注解

@TableName("sys_user")
public class User {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

value

类型: String
默认值: ""

指定数据库表的主键字段名。如果不设置,MyBatis-Plus 将使用实体类中的字段名作为数据库表的主键字段名。

type

类型: Enum
默认值: IdType.NONE

指定主键的生成策略。

IdType 枚举类型定义

  • IdType.AUTO:使用数据库自增 ID 作为主键。
  • IdType.NONE:无特定生成策略,如果全局配置中有 IdType 相关的配置,则会跟随全局配置。
  • IdType.INPUT:在插入数据前,由用户自行设置主键值。
  • IdType.ASSIGN_ID:自动分配 ID,适用于 LongIntegerString 类型的主键。默认使用雪花算法通过 IdentifierGenerator 的 nextId 实现。@since 3.3.0
  • IdType.ASSIGN_UUID:自动分配 UUID,适用于 String 类型的主键。默认实现为 IdentifierGenerator 的 nextUUID 方法。@since 3.3.0
@TableId(value = "id",type = IdType.AUTO)
private Long id;

@TableField

该注解用于标记实体类中的非主键字段,它告诉 MyBatis-Plus 如何映射实体类字段到数据库表字段。如果你的实体类字段名遵循驼峰命名规则,并且与数据库表字段名一致,你可以省略这个注解。

使用该注解的常见场景

  • 成员变量名与数据库字段名不一致
  • 成员变量名以is开头且为布尔值,使用该注解指定

  • 成员变量名与数据库关键字冲突  eg: order

@TableField("`order`")
private Integer order;
  • 成员变量名不是数据库字段  @TableField(exist = false)

value

类型: String
默认值: ""

指定数据库中的字段名。如果你的实体类字段名与数据库字段名不同,使用这个属性来指定正确的数据库字段名。

exist

类型: boolean
默认值: true

指示这个字段是否存在于数据库表中。如果设置为 false,MyBatis-Plus 在生成 SQL 时会忽略这个字段。

typeHandler

类型: Class<? extends TypeHandler>
默认值: UnknownTypeHandler.class

类型处理器,用于指定在数据库操作中如何处理特定字段的值。这个属性允许您自定义字段值的转换逻辑,以适应特定的数据类型或业务需求。

详细说明

  • 当 typeHandler 属性未设置(即使用默认值 UnknownTypeHandler.class)时,MyBatis-Plus 将使用默认的类型处理器来处理字段值。

  • 当 typeHandler 属性设置为特定的 TypeHandler 子类时,该字段将使用指定的类型处理器进行数据库操作。这可以用于处理自定义类型、特殊数据格式或非标准的数据库类型。

@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;

此外还有诸多注解,详见官方文档

条件构造器

MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。

AbstractWrapper

这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。

QueryWrapper

查询名字中带“o”、存款大于等于1000元的人的id、username、info、balance字段

QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id","username","info","balance")
                .like("username","o")
                .ge("balance",1000);
List<User> users = userMapper.selectList(wrapper);

更改jack的余额

User user = new User();
user.setBalance(1699);
QueryWrapper<User> wrapper = new QueryWrapper<User>()
        .eq("username","jack");
userMapper.update(user,wrapper);

UpdateWrapper

使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。

扣除多个用户余额200

List<Long> ids = List.of(1L,2L,3L);
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .setSql("balance = balance - 200")
                        .in("id",ids);
userMapper.update(wrapper);

LambdaQueryWrapper

这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性可维护性,尤其是在字段名可能发生变化的情况下。

采用反射机制,查询名字中带“o”且余额>=1000的用户的id、username、userInfo、balance字段

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
    .select(User::getId,User::getUsername,User::getInfo,User::getBalance)
    .like(User::getUsername,"o")
    .ge(User::getBalance,1000);
List<User> users = userMapper.selectList(wrapper);

LambdaUpdateWrapper

类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。

自定义SQL

利用MybatisPlus中的Wrapper构建自定义的where条件,自定义SQL语句中的剩余部分

构建条件,传入自定义方法并调用

List<Long> ids = List.of(1L,2L,4L);
int amount = 200;
//定义条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
        .in("id",ids);
//调用自定义方法
userMapper.updateBalanceByIds(wrapper,amount);

在mapper方法参数中用@Param注解声明Wrapper变量名称

//void updateBalanceByIds(@Param("ew") QueryWrapper<User> wrapper,@Param("amount") int amount)  一定是 ew ,也可以用下面的常量类
void updateBalanceByIds(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper,@Param("amount") int amount);

自定义sql,使用Wrapper条件

<update id="updateBalanceByIds">
        update user
        set balance = balance - #{amount}
            ${ew.customSqlSegment}
</update>

Service接口

基础使用

IService 是 MyBatis-Plus 提供的一个通用 Service 层接口,它封装了常见的 CRUD 操作,包括插入、删除、查询和分页等。通过继承 IService 接口,可以快速实现对数据库的基本操作,同时保持代码的简洁性和可维护性。

Service接口继承Iservice接口

public interface IUserService extends IService<User> {
}

Service接口实现类继承ServiceImpl<M extends BaseMapper<T>, T>

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{
}

IService 接口中的方法命名遵循了一定的规范,如 get 用于查询单行,remove 用于删除,list 用于查询集合,page 用于分页查询,这样可以避免与 Mapper 层的方法混淆。

当IService接口中的方法不足以满足需求时,需自定义方法,在Service实现类中调用mapper时无需再次注入,使用继承而来的baseMapper(其实就是UserMapper)即可

Lambda方法

lambdaQuery

查询满足条件的用户

使用list方法需new Wrapper

使用lambdaQuery直接指定条件即可

其中第一个参数为条件,满足条件执行判断

public List<User> queryUsers(UserQuery userQuery) {
        return lambdaQuery()
                .like(userQuery.getUsername() != null, User::getUsername, userQuery.getUsername())
                .eq(userQuery.getStatus() != null, User::getStatus, userQuery.getStatus())
                .ge(userQuery.getMinBalance() != null, User::getBalance, userQuery.getMinBalance())
                .le(userQuery.getMaxBalance() != null, User::getBalance, userQuery.getMaxBalance())
                .list();
    }
lambdaUpdate

扣减用户余额,当余额为0时冻结

lambdaUpdate()
        .set(User::getBalance,user.getBalance()-money)
        .set(user.getBalance()-money==0,User::getStatus,UserStatus.FROZEN)
        .eq(User::getId,id)
        .eq(User::getBalance,user.getBalance())//乐观锁
        .update();//真正执行update

批量新增

for循环一条一条新增(速度极差,不推荐)

        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            userService.save(buildUser(i));
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));

IService的批量插入(基于预编译的批处理,性能较好,与上面不同是上面每一条都发起一次网络请求然后插入一条,该方法每1000条发起一次请求然后执行一千条sql语句)

        List<User> list = new ArrayList<>(1000);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            list.add(buildUser(i));
            if (i%1000==0){
                userService.saveBatch(list);
                list.clear();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));

mysql开启rewriteBatchedStatements=true参数

这种情况下在执行批量操作时会将多条sql语句重写成一条sql语句,性能得到极大提升

代码生成器

下载该插件

配置数据库信息

生成代码

Db Kit

Db Kit 是 Mybatis-Plus 提供的一个工具类,它允许开发者通过静态调用的方式执行 CRUD 操作,从而避免了在 Spring 环境下可能出现的 Service 循环注入问题,简化了代码,提升了开发效率。

与IService不同的是,当参数为 Wrapper 时,需要在 Wrapper 中传入 Entity 或者 EntityClass,以便寻找对应的 Mapper。

// 假设有一个 User 实体类和对应的 BaseMapper

// 根据 id 查询单个实体
User user = Db.getById(1L, User.class);

// 根据 id 查询多个实体
List<User> userList = Db.listByIds(Arrays.asList(1L, 2L, 3L), User.class);

// 根据条件构造器查询
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery(User.class)
    .eq(User::getStatus, "active");
List<User> activeUsers = Db.list(queryWrapper);

// 插入新实体
User newUser = new User();
newUser.setUsername("newUser");
newUser.setAge(25);
boolean isInserted = Db.insert(newUser);

// 根据 id 更新实体
User updateUser = new User();
updateUser.setId(1L);
updateUser.setUsername("updatedUser");
boolean isUpdated = Db.updateById(updateUser);

// 根据条件构造器更新
LambdaUpdateWrapper<User> updateWrapper = Wrappers.lambdaUpdate(User.class)
    .set(User::getAge, 30)
    .eq(User::getUsername, "updatedUser");
boolean isUpdatedByWrapper = Db.update(null, updateWrapper);

// 根据 id 删除实体
boolean isDeleted = Db.removeById(1L);

// 根据条件构造器删除
LambdaDeleteWrapper<User> deleteWrapper = Wrappers.lambdaDelete(User.class)
    .eq(User::getStatus, "inactive");
boolean isDeletedByWrapper = Db.remove(deleteWrapper);

// 批量插入
List<User> batchUsers = Arrays.asList(
    new User("user1", 20),
    new User("user2", 22),
    new User("user3", 24)
);
boolean isBatchInserted = Db.saveBatch(batchUsers);

// 批量更新
List<User> batchUpdateUsers = Arrays.asList(
    new User(1L, "user1", 21),
    new User(2L, "user2", 23),
    new User(3L, "user3", 25)
);
boolean isBatchUpdated = Db.updateBatchById(batchUpdateUsers);

逻辑删除

Mybatis提供了逻辑删除功能,无需改变方法调用方式,在底层自动修改CURD的语句,只需在application.yaml文件中配置逻辑删除的字段和值即可

mybatis-plus:
  global-config:
    db-config:
#      逻辑删除字段
      logic-delete-field: deleted
#        逻辑删除的值  默认是1
      logic-delete-value: 1
#      逻辑未删除的值  默认是0
      logic-not-delete-value: 0

自动映射枚举

基本使用

枚举属性使用 @EnumValue 注解,指定枚举值在数据库中存储的实际值。支持枚举类中的任意字段,如序号或编码。

方式一、注解标记

枚举属性使用 @EnumValue 注解,指定枚举值在数据库中存储的实际值。支持枚举类中的任意字段,如序号或编码。

@Getter
@AllArgsConstructor
public enum GradeEnum {
    PRIMARY(1, "小学"),
    SECONDARY(2, "中学"),
    HIGH(3, "高中");

    @EnumValue // 标记数据库存的值是code
    private final int code;
    // 其他属性...
}

方式二、实现接口

实现 IEnum 接口,实现 getValue 方法,指定枚举值在数据库中存储的实际值。支持枚举类中的任意字段,如序号或编码。

@Getter
@AllArgsConstructor
public enum AgeEnum implements IEnum<Integer> {
    ONE(1, "一岁"),
    TWO(2, "二岁"),
    THREE(3, "三岁");

    private final int value;
    private final String desc;

    @Override
    public Integer getValue() {
        return this.value;
    }
}

之后修改全局 defaultEnumTypeHandler

mybatis-plus:
  configuration:
    default-enum-type-handler: xx.xx.xx.MyEnumTypeHandler
如何将序列化枚举值作为前端返回值

Jackson

一、重写toString方法

Spring Boot

@Bean

public Jackson2ObjectMapperBuilderCustomizer customizer() {

return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);

}

Jackson 独立使用

ObjectMapper objectMapper = new ObjectMapper();

objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);

在枚举中重写 toString 方法,以上两种方式任选其一。

二、注解处理

public enum GradeEnum {
    PRIMARY(1, "小学"),
    SECONDORY(2, "中学"),
    HIGH(3, "高中");

    GradeEnum(int code, String descp) {
        this.code = code;
        this.descp = descp;
    }

    @EnumValue
    @JsonValue // 标记响应json值
    private final int code;
}

Fastjson

重写toString方法

全局处理

FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.WriteEnumUsingToString);

局部处理

@JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
private UserStatus status;

Json处理器

MyBatis-Plus 内置了多种 JSON 类型处理器,包括 AbstractJsonTypeHandler 及其子类 Fastjson2TypeHandlerFastjsonTypeHandlerGsonTypeHandlerJacksonTypeHandler 等。这些处理器可以将 JSON 字符串与 Java 对象相互转换。

@Data
@Accessors(chain = true)
@TableName(autoResultMap = true)
public class User {
    private Long id;

    ...

    /**
     * 必须开启映射注解
     *
     * @TableName(autoResultMap = true)
     *
     * 选择对应的 JSON 处理器,并确保存在对应的 JSON 解析依赖包
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    // 或者使用 FastjsonTypeHandler
    // @TableField(typeHandler = FastjsonTypeHandler.class)
    private OtherInfo otherInfo;
}

  • 29
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清欢ovo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值