MyBatis-Plus学习笔记

官方介绍

mybatis-plus可以理解为加强版的mybatis,可以帮我们减少编写mapper中简单的sql语句,你可以理解为IPhone13 和 IPhone13 Plus

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

并且还列出了以下特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

你了解它是一个便捷的Mybatis工具后,我们开始操作

上手练练

准备工作

首先,现在新建数据库mybatisplus

并建两张表分别为category(种类表)和product(商品表):

DROP TABLE IF EXISTS `category`;
CREATE TABLE `category` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `category_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`cid`)
);

DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `product_name` varchar(50) NOT NULL,
  `category_id` int(11) NOT NULL,
  `price` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`pid`)
);

如下图,随便添加一两条数据,这里就不写sql语句了,手动添加:

新建一个maven项目,导入相关依赖包:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
		<!--日志 依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--mybatis-plus 依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--mysql 连接依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>
    </dependencies>

application.properties进行相关的配置 (图中带汉字的需要根据你的配置去修改):

### 数据源配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=UTC
spring.datasource.username=你的mysql用户名
spring.datasource.password=你的mysql密码

##mybatis配置
###扫描mapper文件路径
mybatis-plus.mapper-locations=classpath:mapper/*.xml
mybatis-plus.type-aliases-package=com.melo.entity(修改成你的实体类包名)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

#开启驼峰命名
mybatis-plus.configuration.map-underscore-to-camel-case=true

项目目录结构如此:

虽然我们可以少写mapper中的代码,可是一些复杂逻辑的代码还需要我们自己去编写,所以他其实并不改变正常的mybatis书写

实体类Product代码:

package com.melo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author Melo
 * @Desc 商品实体类
 * @Date 2023/10/26 15:11
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "product") //对应数据库中的表名
public class Product {
    @TableId(type = IdType.AUTO) //标注主键ID(自增)
    private Long pid;
    private String productName;
    private Long categoryId;
    private Double price;
}

接口文件ProductMapper代码:

package com.melo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.melo.entity.Product;
import org.apache.ibatis.annotations.Mapper;

/**
 * @Author Melo
 * @Desc 商品Mapper接口文件
 * @Date 2023/10/26 20:30
 */
@Mapper
public interface ProductMapper extends BaseMapper<Product> {

}

因为使用了mybatis-plus工具,所以ProductMapper需要继承BaseMapper<Product>

其中<>放你需要操作的实体类对象名称

基本操作 CRUD

有了以上的就足够了,我们在测试MybatisplusApplicationTests里面具体练习使用mybatisplus的操作:

使用方法如下:

package com.melo;

import com.melo.entity.Product;
import com.melo.mapper.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
@Slf4j
class MybatisplusApplicationTests {
    @Resource
    private ProductMapper productMapper;

    @Test
    void contextLoads() {
    }

    @Test
    @DisplayName("测试插入数据")
    public void testInsert(){
        Product product = new Product();
        product.setProductName("Macbook笔记本电脑");
        product.setCategoryId(1l);
        product.setPrice(19999.00);
        int result = productMapper.insert(product);
        log.info("testInsert:{}",result);
        log.info("product:{}",product);
    }

    @Test
    @DisplayName("测试查询数据")
    public void testSelectById() {
        Product product = productMapper.selectById(3L);
        log.info("product:{}", product);
    }
    @Test
    @DisplayName("测试查询全部数据")
    public void testSelectList(){
        List<Product> products = productMapper.selectList(null);
        log.info("testSelectList:{}",products);
    }

    @Test
    @DisplayName("测试更新数据")
    public void testUpdateById(){
        Product product = new Product();
        product.setPid(3L);
        product.setProductName("小米手机");
        product.setPrice(3499.00);
        int result = productMapper.updateById(product);
        log.info("测试更新:{}",result);
        log.info("product:{}",product);
    }

    @Test
    @DisplayName("测试删除数据")
    public void testDeleteByid(){
        int result = productMapper.deleteById(4L);
        log.info("testSelectList:{}",result);
    }
}

复杂操作

我们知道在依赖文件中并没有导入mybatis的依赖,只是导入了mybatis-plus工具的依赖,其实只用导入后者也可以进行sql语句的编写,只是大部分情况下用到的都是简单的增删改查操作,所以就使用工具内置的方法。

注:尽量只导入其中一个依赖,否则会产生依赖冲突问题

通过三种复杂情况说明简单举例:

流程和正常写mapper层代码一样,首先定义ProductMapper接口文件:

package com.melo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.melo.entity.Product;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

/**
 * @Author Melo
 * @Desc 商品dao层接口
 * @Date 2023/10/26 15:22
 */
@Mapper
public interface ProductMapper extends BaseMapper<Product> {

    /**
     * 批量插入
     *
     * @param list 列表
     */
    void batchInsert(@Param("list") List<Product> list);

    /**
     * 选择产品类别
     *
     * @return 是List集合但是转为Map
     */
    @MapKey("pid") //将 List 结果集转换为 <key,value> 形式放入 map 结果集,方便快速查找
    List<Map> selectProductWithCategory();

    @MapKey("pid")
    List<Map> selectProductWithCategoryByMap(Map<String,Object> map);
}

ProductMapperxml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.melo.mapper.ProductMapper">

    <insert id="batchInsert">
        insert into product (product_name,category_id,price)
        values
        <foreach collection="ProductList" item="product" separator=",">
            (#{product.productName},#{product.categoryId},#{product.price})
        </foreach>
    </insert>

    <select id="selectProductWithCategory" resultType="java.util.Map">
        select p.pid, p.product_name, c.category_name, p.price
        from product p
                 left join category c
                           on p.category_id = c.cid
    </select>

    <select id="selectProductWithCategoryByMap" resultType="java.util.Map">
        select p.pid, p.product_name, c.category_name, p.price
        from product p
        left join category c on p.category_id = c.cid
        <where>
            <if test="categoryId != null and categoryId != ''">
                and p.category_id=#{categoryId}
            </if>
            <if test="pid != null and pid != ''">
                and p.pid=#{pid}
            </if>
        </where>
    </select>
</mapper>

测试文件只需添加三个测试方法:

@Test
    @DisplayName("测试批量插入商品数据")
    public  void testBatchInsert(){
        List<Product> list = new ArrayList<>();
        list.add(new Product(null,"华为mate40",1l,7000.00));
        list.add(new Product(null,"华为mate40",1l,7000.00));
        list.add(new Product(null,"华为mate40",1l,7000.00));
        productMapper.batchInsert(list);
        log.info("list:{}",list);
    }
    @Test
    @DisplayName("测试查询带分类的商品数据")
    public void testSelectProductWithCategory(){
        List<Map> maps = productMapper.selectProductWithCategory();
        maps.stream().forEach(item->{
            log.info("testSelectProductWithCategory:{}",item);
        });
    }

    @Test
    @DisplayName("测试条件查询带分类的商品数据")
    public void testSelectProductWithCategoryByMap(){
       Map<String,Object> params = new HashMap<>();
       params.put("categoryId",1l);
       params.put("pid",4l);
        List<Map> maps = productMapper.selectProductWithCategoryByMap(params);
        maps.stream().forEach(item->{
            log.info("testSelectProductWithCategoryByMap:{}",item);
        });
    }

别的玩法

分页查询

分页查询在我们的需求中也是十分常见的,之前我们使用的工具为pageHelper

现在mybatis-plus自己实现了分页查询

首先需要进行分页查询的配置:

package com.melo.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;

/**
 * @Author Melo
 * @Desc mybatis-plus配置类
 * @Date 2023/10/26 16:48
 */
@Configuration
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //如果配置多个插件,切记分页最后添加
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        return interceptor;
    }
}

测试:

@Test
    @DisplayName("分页查询")
    public void testSelectPage(){
        QueryWrapper<Product> wrapper = new QueryWrapper<>();
        IPage<Product> page = new Page<>(0,2);
        page = productMapper.selectPage(page,wrapper);
        List<Product> productList = page.getRecords();
        log.info("testSelectPage:{}",productList);
    }

条件构造器

封装了一些条件查询的包装器,简单使用如下:

@Test
    @DisplayName("根据商品名查询商品")
    public void testQueryWrapper(){
        //创建查询条件对象
        QueryWrapper<Product> wrapper = new QueryWrapper<>();
        //设置返回字段
        wrapper.select("product_name","price");
        //添加查询条件
        wrapper.eq("product_name","小米手机")
                .ge("price",2000.00);
        //查询
        List<Product> products = productMapper.selectList(wrapper);
        log.info("testQueryWrapper:{}",products);
    }

点击查看更多关于条件构造器的用法

以上就是本文全部内容,想学习更多的可以去官网继续学习

文章知识点来源:https://baomidou.com/

posted @ 2023-10-26 22:46  Melo70000  阅读(10)  评论(0编辑  收藏  举报