MyBatisPlus

发布于:2025-07-25 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、快速入门

1、入门案例

使用步骤:

        1)引入依赖(引入MyBatisPlus依赖就不需要再引入MyBatis了,它集成了MyBatis和MyBatisPlus的所有功能)

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

把 
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.1</version>
        </dependency>
替换掉即可

          2)自定义Mapper并继承MybatisPlus提供的BaseMapper接口:

public interface UserMapper extends BaseMapper<User> {

注意:继承时要指定泛型为操作实体类的类型 

        3)调用crud方法

优点:1)润物无声:制作增强不做改变,引入他不会对现有工程产生影响,如丝般顺滑。

           2)效率至上:只需要简单配置,即可快速进行单表CRUD操作,从而节省大量时间。

2、常见注解 

MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。

其中约定:1)类名驼峰转下划线作为表名

                   2)名字id的字段作为主键

                   3)变量名驼峰转下划线作为表的字段名

如果实体类不符合约定就需要自己配置,使用提供的注解进行自定义配置。

常见注解:

  •         @TableName:用来指定表名
  •         @TableId:用来指定表中的主键字段信息 
  •         @TableField:用来指定表中的普通字段信息 (使用场景:①成员变量名与数据库字段不一致、②成员变量名以is开头且是布尔值、③成员变量名与数据库关键字冲突、④成员变量不是数据库字段@TableField(exist = false))

这里的id其实可以不用配置,因为字段名相同 。

在MP中,id的自增称为id策略,可以通过type来设置 ,即@TableId(value="id" type = IdType.AUTO),如果设置了id自增的话应该加上注解否则默认雪花算法

id策略有以下常见类型:

  •         AUTO:数据库自增长
  •         INPUT:通过set方法自行输入
  •         ASSIGN_ID:分配ID,由MP提供的,通过雪花算法生成的Long型,20位id       

3、常见配置

大多数的配置都有默认值,因此我们都无需配置。但还有一些是没有默认值的,例如:

  • 实体类的别名扫描包

  • 全局id类型

mybatis-plus: 
    type-aliases-package: com.itheima.mp.domain.po 
    global-config: 
        db-config: 
            id-type: auto # 全局id类型为自增长

需要注意的是,MyBatisPlus也支持手写SQL的,而mapper文件的读取地址可以自己配置:

mybatis-plus: 
    mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,当前这个是默认值。

二、核心功能 

1、条件构造器

MybatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求。

 条件构造方法

方法 说明 示例
eq 等于 = eq("name", "老王")
ne 不等于 <> ne("name", "老王")
gt 大于 > gt("age", 18)
ge 大于等于 >= ge("age", 18)
lt 小于 < lt("age", 30)
le 小于等于 <= le("age", 30)
between BETWEEN 值1 AND 值2 between("age", 18, 30)
notBetween NOT BETWEEN notBetween("age", 18, 30)
like LIKE '%值%' like("name", "王")
notLike NOT LIKE '%值%' notLike("name", "王")
in 字段 IN (value.get(0), value.get(1), ...) in("age", Arrays.asList(18, 20, 22))

部分代码:

 @Test
    /**
     * 查找名字中带o的,存款大于等于1000元的id、username、info、balance
     */
    void testQueryWrapper() {
        //构建查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void testLambdaQueryWrapper() {
        //构建查询条件
        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);
        users.forEach(System.out::println);
    }

    /**
     * 更新用户名为jack的用户的余额为2000
     */
    @Test
    void testUpdateByQueryWrapper() {
        //更新的数据
        User user = new User();
        user.setBalance(2000);
        //更新的条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .eq("username", "jack");
        //执行更新
        userMapper.update(user, wrapper);
    }

    /**
     * 更新id为1,2,4的用户的余额,扣200
     */
    @Test
    void testUpdateWrapper() {
        List<Long> ids = List.of(1L, 2L, 4L);
        //更新的条件
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .setSql("balance = balance - 200")
                .in("id", ids);
        //执行更新
        userMapper.update(null, wrapper);
    }

2、自定义sql

利用MP的Wrapper来构建复杂的where条件,然后自己定义SQL语句中剩下的部分。

        ①基于Wrapper构建where条件

 @Test
    void testCustomSqlUpdate() {
        //1、更新条件
        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方法参数中用Para注解声明wrapper变量名称,必须是ew

  void updateBalanceByIds(@Param("ew") QueryWrapper<User> wrapper,@Param("amount") int amount);

        ③自定义SQL,并使用Wrapper条件

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

3、Service接口

        1)自定义接口继承IService接口。

public interface IUserService extends IService<User> {
}

        2)自定义实现类,实现类自定义接口并继承ServiceImpl类。

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

4、BeanUtil

BeanUtil.copyProperties 与 BeanUtils.copyProperties 的区别

这两个方法都是用于对象属性拷贝的工具方法,但来自不同的工具库,有以下几个关键区别:

1. 来源不同

方法 所属库 Maven依赖
BeanUtil.copyProperties Hutool工具库 cn.hutool:hutool-all
BeanUtils.copyProperties Apache Commons BeanUtils 或 Spring Framework org.apache.commons:commons-beanutils 或 org.springframework:spri

2. 主要区别对比

2.1 Hutool的BeanUtil.copyProperties

  User user = BeanUtil.copyProperties(userDTO, User.class);

特点:

  • 直接创建目标对象:自动实例化目标类

  • 支持更多类型转换:内置更强大的类型转换器

  • 性能优化:Hutool针对反射做了优化

  • 支持别名:可通过注解指定字段映射关系

  • 链式调用:返回目标对象实例

2.2 Apache Commons/Spring的BeanUtils.copyProperties

User user = new User();
BeanUtils.copyProperties(userDTO, user);

特点:

  • 需要预先创建对象:必须先实例化目标对象

  • 基本类型转换:只支持简单的类型转换

  • Spring版本增强:Spring的版本比Apache的更安全

  • 直接修改目标对象:无返回值

3. 功能对比表

特性 Hutool BeanUtil Apache/Spring BeanUtils
是否需要预先创建对象
类型转换能力 强大(支持更多类型) 基础
性能 较高(缓存反射) 一般
字段映射配置 支持@Alias注解 不支持
异常处理 更友好 可能抛BeanException
嵌套对象拷贝 支持 不支持
链式调用 支持 不支持
来源库大小 较大(整个Hutool) 较小

4. 使用场景建议

使用Hutool的BeanUtil当:

  • 需要从DTO直接创建实体对象

  • 涉及复杂类型转换

  • 需要处理字段别名映射

  • 项目已经使用了Hutool工具库

使用Spring的BeanUtils当:

  • 已经存在目标对象实例

  • 只需要简单属性拷贝

  • 项目已经是Spring环境

  • 希望减少额外依

5、实战

@Autowired注解并不推荐

推荐构造函数注解,但是构造函数比较麻烦,可以使用lombok的注解@RequiredArgsConstructor

@RestController
@RequestMapping("/users")
@Api(tags="用户管理接口")
@RequiredArgsConstructor //添加该注解代替@Autowired
public class UserController {

    private final IUserService userService;

 lambdaqurey()方法,不用写wrapper并且可以直接链式编程出查询语句即.list()

@Override
    public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
        return lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .ge(minBalance != null, User::getBalance, minBalance)
                .le(maxBalance != null, User::getBalance, maxBalance)
                .list();

 lambdaUpdate()方法

        //4、扣减余额
       // baseMapper.deductBalance(id, money);
        int remainBalance = user.getBalance() - money;
        lambdaUpdate()
                .set(User::getBalance, remainBalance)
                .set(remainBalance == 0 ,User::getStatus,2)
                .eq(User::getId, id)
                .update();

rewriteBatchedStatements 是 MySQL JDBC 驱动程序的一个重要配置参数,主要用于优化批量(Batched)SQL 语句的执行性能。该参数默认为false,进行的批处理操作默认会转化为单个的SQL,当改为true是,会进行真正的批处理。

配置:

url: jdbc:mysql://localhost:3306/db?rewriteBatchedStatements=true

三、扩展功能

1、代码生成

        1)在file->settings->Plugins中搜索mybatisplus安装插件

        2)重启idea,上方找到other打开

        3)填写对应参数 

        4)点击另一个按钮,进行一些配置

2、静态工具

    @Override
    public UserVO queryUserAddressesById(Long id) {
        //1、查询用户
        User user = getById(id);
        if(user == null || user.getStatus() == 2){
            throw new RuntimeException("用户状态异常");
        }
        //2、查询地址
        Db.lambdaQuery(Address.class) //静态方法,可以不用注入address的service
                .eq(Address::getUserId , id)
                .list();
        return null;

通过Stream流按照userid进行分组,并存储到map中

addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));

3、逻辑删除

逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据。思路如下:

  • 在表中添加一个字段标记数据是否被删除
  • 删除时标记为1
  • 查询时只查询标记为0的数据

例如逻辑删除的字段为delete 删除操作使用update: update user set delete = 1 where id  = 1 and deleted = 0

在mybatisPlus中,其提供了逻辑删除功能,无需改变方法调用的方式,而是在底层帮我们自动修改CRUD的语句。我们要做的就是在application.yaml文件中配置逻辑删除的字段名称和值即可:

mybatis-plus:
  type-aliases-package: com.itheima.mp.domain.po
  global-config:
    db-config:
      id-type: auto
      logic-delete-field: deleted #配置逻辑删除字段

4、枚举处理器

枚举

是一种特殊类,格式:

注意:

  • 枚举中的第一行,只能写一些合法的标识符(枚举项),多个名称用,隔开。
  • 这些枚举项本质是常量,每一个枚举项都会记录              枚举类的一个对象。

需要在配置文件中添加配置

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

编写类

@Getter   //自动生成getter方法
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "冻结"),
    ;
    @EnumValue   //写在哪个属性,哪个属性与数据库对应
    private final int value;
    @JsonValue   //写在哪个属性,哪个属性就在前端展示,,默认是枚举项的名字如NORMAL
    private final String desc;

    UserStatus(int value, String desc){
        this.value = value;
        this.desc = desc;
    }
}

在使用时就可以使用 UserStatus.FREEZE 或 UserStatus.NORMAL 了,更易阅读

5、JSON处理器

首先要定义实体类

将字段改为实体类类型

加上@TableFiled(typeHandler = JacksonTypeHandler.class)注解

开启自动结果集映射 在类注解:@TableName中加上 atuoResultMap = true

@Data
@TableName(value = "user", autoResultMap = true)
public class User {


    /**
     * 详细信息
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private UserInfo info;


}

四、插件功能

1、分页查询

编写配置类

@Configuration
public class MyBatisConfig {

    @Bean
    public MybatisPlusInterceptor  MybatisPlusInterceptor(){
     MybatisPlusInterceptor interceptor =   new MybatisPlusInterceptor();
     //创建分页插件
     PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
     paginationInnerInterceptor.setMaxLimit(1000L);
     //添加分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

 

测试使用

 OrderItem中传递 排序的字段 以及升序还是降序


网站公告

今日签到

点亮在社区的每一天
去签到