SpringBoot整合Mybatis-Plus快速开发

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。

官方文档:https://mp.baomidou.com/guide/

SpringBoot整合MP有以下几个步骤:

1、引入Mybatis-Plus依赖

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

2、在 yaml 配置文件中配置数据源和要扫描加载的 mappper. xml映射文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/spring-boot-example?useUnicode=true&characterEncoding=utf8
    username: xxx
    password: xxxxxx
    hikari:
      #最小空闲连接数
      minimum-idle: 10
      #连接池最大连接数
      maximum-pool-size: 20

mybatis-plus:
  mapper-locations: classpath:mapper/*Mapper.xml

3、在启动类上加上配置 dao 层接口的扫描

@SpringBootApplication
@MapperScan("com.bin.dao") // 扫描com.bin.dao包下的所有Mapper接口
public class SpringbootFastApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootFastApplication.class, args);
    }
}

以下通过几个案例来看看Mybatis-Plus是如何快速、高效的开发

一、使用通用BaseMapper和通用Service CRUD

MP已经对一些常用的CRUD操作做了封装,我们只需要继承它提供的BaseMapper和ServiceImpl即可拥有大多数常见的增删查改功能。

继承 BaseMapper

public interface UserMapper extends BaseMapper<User> {
}

先创建一个UserMapper继承自 BaseMapper,传入的泛型为User,User实体类如下:

@TableName("sys_user")
public class User {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private String name;
    private Integer age;
	// 省略getter和setter
}

@TableName("sys_user"):含义是User实体类对应的是数据库的 sys_user 表。如果对应的数据库表时user表,那这行注解 @TableName("sys_user") 就可以省略,MP的默认规则会把User实体映射到user表
@TableId(value = "id", type = IdType.AUTO)标记此字段对应的是数据库表的主键,主键id的类型为自增长

接着就可以直接在service层使用:
在这里插入图片描述
基础的增删查改不用在mapper.xml中写SQL语句了,开发就是这么的快速。

继承 ServiceImpl

@Service
public class UserService extends ServiceImpl<UserMapper, User> implements IUserService {
}
public interface IUserService extends IService<User> {
}
  • ServiceImplBaseMapper 做了更进一步的封装,我们让自己的 UserService 实现类直接继承 ServiceImpl,并在泛型中传入对应的 UserMapper 和User实体类
  • IUserService 接口继承MP提供的 IService 接口,并在泛型中传入对应的User实体类

这样就同样可以在service层中拥有丰富的CRUD功能,接着就可以直接在controller层使用:
在这里插入图片描述
service层基础的增删查改代码也不用写了,就是这么的快速。

二、分页查询

1、配置分页插件

@SpringBootApplication
@MapperScan("com.bin.dao") // 扫描com.bin.dao包下的所有Mapper接口
public class SpringbootFastApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootFastApplication.class, args);
    }

	// 分页插件拦截器
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
}

2、在MP提供的分页查询方法中直接传入MP提供的分页对象

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    private IUserService userService;
    
    @RequestMapping("queryPage")
    public IPage queryPage() {
    	// MP的分页对象,这里要查询第2页,页大小是2
        Page page = new Page(2, 2);
        return userService.page(page);
    }
}

执行时生成的SQL语句如下
在这里插入图片描述
最终接口返回结果如下
在这里插入图片描述
瞬间就完成了分页功能 ^_^

若是需要在XML中自定义分页查询,操作如下

  • 对应的XML的SQL和Mapper接口
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bin.dao.UserMapper">

    <select id="selectPage" resultType="com.bin.entity.User">
        select * from sys_user where age = #{age}
    </select>

</mapper>
public interface UserMapper extends BaseMapper<User> {
    IPage<User> selectPage(Page<?> page, Integer age);
}

当有传递Page 对象作为参数时,MP会自动加上分页查询, page参数必须放在第一位,否则会报错
大功告成了,生成执行的SQL如下
在这里插入图片描述

三、通用枚举处理

在mybatis中默认支持的类型转换器无法处理枚举类型,所以如果想在实体类中以枚举类型作为属性的话,需要让mybatis去支持我们定义的枚举类,让mybatis在传入数据和返回数据的时候帮我们做类型的转换。

1、在配置文件中加入枚举类所在的包扫描

mybatis-plus:
  mapper-locations: classpath:dao/*Mapper.xml
  type-enums-package: com.bin.constant.enums

这样MP就能帮我们识别到需要转换的枚举类型

2、定义一个枚举类

import com.baomidou.mybatisplus.annotation.EnumValue;

public enum OrderStatusEnum {
    WAIT_PAY(1, "待支付"),
    PAID(2, "已支付"),
    CANCEL(3, "已取消"),
    FINISH(4, "已完成");
    
    OrderStatusEnum(int code, String desc){
        this.code = code;
        this.desc = desc;
    }
    
    @EnumValue
    private int code;
    private String desc;

    public int getCode() {
        return this.code;
    }
    public String getDesc() {
        return this.desc;
    }
    @Override
    public String toString() {
        return this.desc;
    }
}

在定义的枚举类中,在code属性上加上 @EnumValue,表示我们将会以code的值去对应到数据表的字段值

3、在Order类中加入OrderStatusEnum 作为属性

@TableName("t_order")
public class Order implements Serializable {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private String orderNo;
    private OrderStatusEnum status;
    // 省略getter和setter

对应数据库表如下:
在这里插入图片描述
说明:实体类中的status字段是枚举类型的,数据库表中的status字段是tinyint类型的

4、验证一下MP的类型转换器效果

@Service
@Transactional
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Override
    public boolean updateOrderStatus(Integer orderId) {
        Order order = getBaseMapper().selectById(orderId);
        System.out.println(order);
        order.setStatus(OrderStatusEnum.CANCEL);
        return getBaseMapper().updateById(order) == 1;
    }
}

在这里插入图片描述

  • 执行SQL查询返回结果时,MP自动把数据库返回的 status 字段转换为了 OrderStatusEnum 类对象(Integer类型转换为了枚举类型
  • 执行SQL更新时,MP自动把 OrderStatusEnum 类对象转换成了整形值(枚举类型转换为了Integer类型
四、乐观锁插件

乐观锁:是对同一资源并发访问控制的一种思想,因为是乐观的,所以它认为每次当前用户读取数据时,别人都不会修改数据,直到最终用户要修改数据时,再判断一下这个数据是否已经被别人修改。

那如何判断数据是否被修改过?

可以在数据库表上增加多一个 version 字段,当某条记录修改成功时,就在这条记录的 version 上 +1,因此是以版本号的方式来判断。

SQL示例:

UPDATE t_order SET order_no=?, version=(读取时的version + 1), status=? WHERE id=? AND version=(读取时的version) 
  • 如果数据已经被修改,那么 version 就会被+1,在更新时发现版本号已经不匹配,因此数据更新不成功。
  • 如果数据没有被修改过,此时 version 和之前读取时的一样,因此操作数据更新就会成功。

具体案例:
小明和小红每天都需要共同处理后台的审核订单,审核通过后系统会发送一条通知给用户。为了避免两个人会同一时刻操作到同一条订单的审核,导致误操作或者脏数据,于是就可以引入在订单记录上加版本号的方案。

在MP中实现乐观锁有如下2个步骤:

1、在启动类配置上OptimisticLockerInterceptor

@SpringBootApplication
@MapperScan("com.bin.dao") // 扫描com.bin.dao包下的所有Mapper接口
public class SpringbootFastApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootFastApplication.class, args);
    }
    
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

2、在User实体类中对应的version字段上加@Version注解

@TableName("t_order")
public class Order implements Serializable {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private String orderNo;
    private Integer status;
    @Version
    private Integer version;
    // 省略getter和setter
}

具体业务实现如下:

@Service
@Transactional
public class OrderService extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Override
    public boolean updateOrderStatus(Integer orderId, Integer version) {
        Order order = getBaseMapper().selectById(orderId);
        order.setStatus(OrderStatusEnum.FINISH);
        order.setVersion(version);
        int i = getBaseMapper().updateById(order);
        if (i == 1) {
            // 发送消息通知用户
//            sendMsg();
            return true;
        }
        return false;
    }
}
@RequestMapping("updateOrderStatus/{orderId}/{version}")
public boolean updateOrderStatus(@PathVariable("orderId") Integer orderId, @PathVariable("version") Integer version) {
    System.out.println(Thread.currentThread().getName());
    return orderService.updateOrderStatus(orderId, version);
}

比如小明和小红两个人同时读取到 orderId=1 的这条订单,当时这条订单的 version 为 8,接着两人同时操作审核通过,前端调用接口时把获取到的版本号传递到接口,当其中一人的请求被处理成功时,会把该订单记录的 version 变成 9,那么另外一个人的操作就不会成功了。

最终执行效果如下:
在这里插入图片描述
乐观锁插件会自动把原本的 version = 8 作为过滤条件,并在执行更新时把version更新为 version + 1。

MP在开发中确实是一把利器,帮助我们更快速高效的开发。MP中还有很多丰富的插件扩展,具体查看官方文档:https://mp.baomidou.com/guide/

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值