MybatisPlus

本文详细介绍了MyBatisPlus的简介、CRUD操作、分页查询、条件构造器Wrapper的使用,以及全局ID生成策略和代码生成器的配置与应用。通过实例展示了如何使用MyBatisPlus进行数据库访问和业务处理,包括插入、删除、更新、查询等基本操作,并演示了自定义分页查询和条件构造器的高级用法。
摘要由CSDN通过智能技术生成

一、MybatisPlus简介

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

框架结构

在这里插入图片描述

二、MP-CRUD快速使用

数据库表结构
在这里插入图片描述

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `t_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `age` int(0) NULL DEFAULT NULL COMMENT '年龄',
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, 'Jone', 18, 'test1@baomidou.com');
INSERT INTO `t_user` VALUES (2, 'Jack', 20, 'test2@baomidou.com');
INSERT INTO `t_user` VALUES (3, 'Tom', 28, 'test3@baomidou.com');
INSERT INTO `t_user` VALUES (4, 'Sandy', 20, 'test4@baomidou.com');
INSERT INTO `t_user` VALUES (5, 'Billie', 24, 'test5@baomidou.com');
INSERT INTO `t_user` VALUES (7, 'tatat', 22, '614039502@qq.com');
INSERT INTO `t_user` VALUES (8, 'pang', 22, '614039502@qq.com');

SET FOREIGN_KEY_CHECKS = 1;

实体类

package cn.guet.quick_start.pojo;

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

/**
 * @author pangjian
 * @ClassName User
 * @Description
 * @date 2021/5/20 13:44
 */
@Data
@AllArgsConstructor
@TableName("t_user")
public class User {
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    @TableField("t_name")
    private String name;
    private Integer age;
    private String email;
    
    /*
    @TableField(exist = false)
    private String salary;
    */
}

注解使用

  • @TableId(value = “id”,type = IdType.AUTO)

如果你的实体类有一个id属性,mp会默认它为主键,如果你没有设置id值,它会帮你生成一个全局唯一的id值,因为主键一定是唯一的,但数据库主键已经设计了自增策略,我不想它帮我生成,如果数据库设置了id自增,改变type就可以实现id自增,原来默认是分布式全局唯一ID,现在变成了主键自增策略

  • @TableField(“t_name”)

我们数据库表的字段名没有name,mp默认是把成员变量名当作表字段名去执行sql语句,我们可以使用该注解去映射数据库字段名

  • @TableField(exist = false)

把该属性设置为不是数据库字段

  • @TableName(“t_user”)

mp会默认将pojo类名当作表名,如果类名和表名不一致可以使用注解,我们可以使用该注解去映射数据库表名

mybatisplus-实现数据库访问(Mapper层)

前提条件
package cn.guet.quick_start.Mapper;

import cn.guet.quick_start.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author pangjian
 * @Interface UserMapper
 * @Description 继承BaseMapper<T>,泛型填写自己要操作的实体类,就可以不用写sql语句直接调用内置通用的Mapper,实现对单表的大部分CURD
 * @date 2021/5/20 13:46
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
测试
插入
@Test
void insert() {
	// id不用设值,直接用数据库的主键自增策略
    User user = new User(null,"nihao",22,"614039502@qq.com");
    userMapper.insert(user);
    // 插入后可以立即返回主键
    System.out.println("插入记录的主键:======"+user.getId());
}
删除
@Test
void delete() {
	// 按id=9的条件去删除该记录
    userMapper.deleteById(9);
}
更新
@Test
void update() {
    User user = new User(8,"pmc",21,"614039502@qq.com");
    // 更新id为8的用户信息
    userMapper.updateById(user);
    System.out.println(user);
}
查询
@Test
void queryListByMap() {
    Map<String,Object> map = new HashMap<>();
    map.put("age",20);
    map.put("email","614039502@qq.com");
    // 查询age为20并且id是2的user信息,map的构造的查询条件只能是等于
    List<User> users1 = userMapper.selectByMap(map);
    System.out.println("查看1列表信息:======="+users1);
    //查询所有
    List<User> users = userMapper.selectByMap(null);
    System.out.println("查看2列表信息:======="+users);

}

mybatisplus-实现业务访问(Service层)

前提条件
package cn.guet.quick_start.service;

import cn.guet.quick_start.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * @author pangjian
 * @Interface UserService
 * @Description 业务层接口继承IService<T>接口,泛型写自己要操作的实体类,
 * @date 2021/5/20 14:57
 */
public interface UserService extends IService<User> {
}
package cn.guet.quick_start.service.impl;

import cn.guet.quick_start.Mapper.UserMapper;
import cn.guet.quick_start.pojo.User;
import cn.guet.quick_start.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * @author pangjian
 * @ClassName UserServiceImpl
 * @Description 如果单单实现了UserService,要实现很多接口,mp为了不麻烦,会让我们去继承一个基类,2个泛型:要操作的Mapper接口和实体类
 * @date 2021/5/20 14:58
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
测试
记录没有插入,有则更新的业务
@Test
void saveOrUpdate() {
    User user = new User(8,"pang",22,"614039502@qq.com");
    // 根据id去查询,没有则插入,有则更新
    userService.saveOrUpdate(user);
}

三、MP-分页查询

前提条件

package cn.guet.quick_start.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 pangjian
 * @ClassName MPconfig
 * @Description 配置类,采用官方文档的最新版配置方式
 * @date 2021/5/20 15:25
 */
@Configuration
public class MPconfig {

   	// 分页插件,要指定数据库类型
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

测试

/**
 * @Description:要配置分页插件
 * @return void
 * @date 2021/5/20 15:24
*/
@Test
void page() {
    // 第一页显示4条
    IPage<User> iPage = new Page<>(1,4);
    // 返回一个IPage对象,一定要指定泛型
    IPage<User> page = userService.page(iPage);
    //当前分页的所有的数据,根据Ipage对象定好的规则
    List<User> records = page.getRecords();
    System.out.println("==========="+records);
    // 当前分页的总页数
    System.out.println("总页数"+page.getPages());
    // 设置每页显示的条数
    // page.setSize(2);
    // 当前页
    System.out.println("当前页"+page.getCurrent());
    // 每页显示的条数
    System.out.println("每一页显示的条数"+page.getSize());
}

项目常用的自定义分页实现

xml编写

<?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="cn.guet.quick_start.Mapper.UserMapper">
    
    <select id="selectByAge" resultType="cn.guet.quick_start.pojo.User">
        SELECT * FROM T_USER WHERE AGE=#{age}
    </select>

</mapper>

Mapper编写

@Mapper
public interface UserMapper extends BaseMapper<User> {

    IPage<User> selectByAge(IPage page, Integer age);

}

Service编写

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public IPage<User> selectByAge(Integer age) {
        // 第一页显示两条数据,简单就写死了,如果项目,这两个值通过方法传参设置的
        IPage<User> iPage = new Page<>(1,2);

        iPage = userMapper.selectByAge(iPage,age);

        return iPage;
    }
}

测试

@Test
public void pageTest(){

    IPage<User> iPage = userService.selectByAge(20);
    System.out.println("分页数据==========="+iPage.getRecords());
    System.out.println("总页数====="+iPage.getPages());
}

四、MP-条件构造器Wrapper

用于条件不是对等条件的查询条件语句,比如模糊查询等

测试

@Test
public void list(){
	// 继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    // 相当于执行了 SELECT t_name,age FROM t_user WHERE (email = ?)
    queryWrapper
            .select("t_name","age")
            .eq("email","614039502@qq.com");
    System.out.println("======="+userService.list(queryWrapper));
}
  • 目前有一个不懂的地方就是查询字段为t_name,pojo实体类类用了注解@TableField(“t_name”)去映射了t_name,但查询结果注入属性为空,可能要做一些ResultMap映射

官方文档详细使用说明

五、MP-全局id生成策略

目前我们的主键生成策略是只应用于了User,假如我们要全局配置

mybatis-plus:
  global-config:
    db-config:
      id-type: auto

就不需要每个类的id都要加注解去说明了

六、MP-代码生成器

依赖包

<!--代码生成器依赖-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>
<!--模板引擎-->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

测试

package cn.guet.generator;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author pangjian
 * @ClassName GeneratorApp
 * @Description TODO
 * @date 2021/5/21 13:43
 */

public class GeneratorApp {


    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {

        /**
         * @Description:构造代码生成器对象
         * @date 2021/5/21 14:41
        */
        AutoGenerator mpg = new AutoGenerator();

        /**
         * @Description:全局配置
         * @date 2021/5/21 14:05
        */
        GlobalConfig gc = new GlobalConfig();
        // 获得当前项目路径,我们不希望生成在父工程里面,而是在子模块里面,需要加一级 /generator
        String projectPath = System.getProperty("user.dir")+"/generator";
        System.out.println(projectPath); // D:\springboot-study\mybatis-plus
        // 设置生成路径,包是从另外的配置去设置,这里只是全局配置
        gc.setOutputDir(projectPath + "/src/main/java");
        // 每个类里面生成作者
        gc.setAuthor("pangjian");
        // 代码生成后是否要打开所在文件夹,一般我们设置为不需要
        gc.setOpen(false);
        // 实体属性 Swagger2 注解,要导入Swagger2的相关依赖,它根据数据库表注释去生成的
        gc.setSwagger2(true);
        // 会在mapper.xml生成一个基础的<ResultMap> 映射所有字段
        gc.setBaseResultMap(true);
        // 同文件的生成覆盖,就不会执行两次,生成两个内容相同的文件了
        gc.setFileOverride(true);
        // 设置生成的实体类名:直接用表名
        gc.setEntityName("%s");
        // 设置生成的Mapper类名:直接用表名加Mapper来命名,%s就是表名,后面拼接上Mapper
        gc.setMapperName("%sMapper");
        // 设置mapper.xml文件名
        gc.setXmlName("%sMapper");
        // 设置业务接口名称
        gc.setServiceName("%sService");
        // 设置业务实现类名称
        gc.setServiceImplName("%sServiceImpl");

        // 全局配置设置到代码生成器对象里面去
        mpg.setGlobalConfig(gc);


        /**
         * @Description:数据源配置
         * @date 2021/5/21 14:05
        */
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mp?serverTimezone=UTC&userUnicode=true&characterEncoding=utf-8&userSSL=false");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");

        mpg.setDataSource(dsc);


        /**
         * @Description:包配置,控制生成的代码放在哪个包下面,全局配置只指定到了/src/main/java下
         * @date 2021/5/21 14:08
        */
        PackageConfig pc = new PackageConfig();
        // 设置模块名,也就是/src/main/java+域名最后一级的包名(也是模块名,它的目录下就是springboot的入口启动器)
        pc.setModuleName(scanner("模块名"));
        // 设置项目建设时候的域名,也就是/src/main/java,接下来的包路径
        pc.setParent("cn.guet");
        mpg.setPackageInfo(pc);


        /**
         * @Description:自定义配置
         * @date 2021/5/21 14:32
        */
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 我们用什么模板就要配置什么模板路径
        String templatePath = "/templates/mapper.xml.vm";


        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!,控制生成xml文件的路径
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);


        /**
         * @Description:配置模板
         * @date 2021/5/21 14:38
        */
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        // 把默认生成的xml文件路径给关掉,只在自定义配置路径下生成
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);


        /**
         * @Description:策略配置
         * @date 2021/5/21 14:13
        */
        StrategyConfig strategy = new StrategyConfig();
        // 表名的生成策略:下划线转驼峰命名t_user->tUser
        strategy.setNaming(NamingStrategy.underline_to_camel);
        // 列名的生成策略:下划线转驼峰命名last_name->lastName
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // 没有就注释掉
        // strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        // 实体类是否支持lombok
        strategy.setEntityLombokModel(true);
        // controller类是否用@RestController注解
        strategy.setRestControllerStyle(true);
        // 公共父类,Controller没有父类注释掉
        // strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        // strategy.setSuperEntityColumns("id");

        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        // 驼峰转连字符,比如表名pms_product -->controller类 @RequestMapping("/pmc/pms_product"),false的话是pmsProduct
        strategy.setControllerMappingHyphenStyle(false);
        // 过滤掉表前缀,生成的所有类就不会带前缀
        strategy.setTablePrefix("t_");
        mpg.setStrategy(strategy);
        // 用默认的不用设置
        // mpg.setTemplateEngine(new FreemarkerTemplateEngine());


        /**
         * @Description:代码生成器对象执行自动生成代码
         * @date 2021/5/21 14:42
        */
        mpg.execute();

    }
}

结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值