7.SSM-MyBatisPlus

1.MyBatisPlus简介

1.1 入门案例

建表sql

CREATE DATABASE mybatisplus_db;
USE mybatisplus_db;

CREATE DATABASE IF NOT EXISTS mybatisplus_db CHARACTER SET utf8;
USE mybatisplus_db;
CREATE TABLE USER (
id BIGINT(20) PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(32) NOT NULL,
PASSWORD VARCHAR(32) NOT NULL,
age INT(3) NOT NULL ,
tel VARCHAR(32) NOT NULL
);
INSERT INTO USER VALUES(1,'Tom','tom',3,'18866668888');
INSERT INTO USER VALUES(2,'Jerry','jerry',4,'16688886666');
INSERT INTO USER VALUES(3,'Jock','123456',41,'18812345678');
INSERT INTO USER VALUES(4,'传智播客','itcast',15,'4006184000');

实验步骤
① 创建SpringBoot项目,勾选MySQL Driver
② 添加依赖坐标

<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.4.1version>
dependency>
<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.16version>
dependency>

注意事项:由于mp未被收录到idea的系统内置配置,无法直接选择加入

③ 配置数据库参数

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://192.168.1.224:3306/mybatisplus_db
    username: root
    password: 123456

④ 创建domain.User对象

package com.example.domain;

public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", tel='" + tel + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }
}

⑤ 定义数据接口,继承BaseMapper

package com.example.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.domain.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao extends BaseMapper<User> {
}

⑥ 测试类中注入dao接口,测试功能

package com.example;

import com.example.dao.UserDao;
import com.example.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SpringbootMybatisplusApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);
    }

}

1.2 MyBatisPlus概述

MyBatisPlus是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率
官网:https://baomidou.com/

MyBatisPlus特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

2.标准数据层开发

标准数据层CRUD功能

功能 自定义接口 MP接口
新增 boolean save(T t) int insert(T t)
删除 boolean delete(int id) int deleteById(Serializable id)
修改 boolean update(T t) int updateById(T t)
根据id查询 T getById(int id) T selectById(Serializable id)
查询全部 List getAll() List selectList()
分页查询 pageInfo getAll(int page,int size) IPage selectPage(IPage page)
按条件查询 List getAll(Condition condition) IPage selectPage(Wrapper queryWrapper)

测试MP接口

package com.example;

import com.example.dao.UserDao;
import com.example.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SpringbootMybatisplusApplicationTests {

    @Autowired
    private UserDao userDao;

    @Test
    void testSave(){
        User user = new User();
        user.setAge(11);
        user.setName("小王");
        user.setPassword("xiaowang");
        user.setTel("123456");
        userDao.insert(user);
    }

    @Test
    void testDelete(){
        userDao.deleteById(1530454523057905666L);
    }

    @Test
    void testGetById(){
        User user = userDao.selectById(1L);
        System.out.println(user);
    }

    @Test
    void testUpdate(){
        User user = new User();
        user.setId(1L);
        user.setName("Tom666");
        userDao.updateById(user);
    }

    @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);
    }

}

lombok
导入依赖坐标

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <scope>providedscope>
dependency>

使用lombok注解创建实体类

package com.example.domain;

import lombok.*;

//@Setter
//@Getter
//@ToString
//@NoArgsConstructor
//@AllArgsConstructor
//@EqualsAndHashCode
@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
}

@Data可以代替get/set方法,有参/无参构造器方法,toString方法,hashCoded方法,equals方法等

2.1 分页功能

① 设置分页拦截器作为Spring管理的bean

package com.example.config;

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;

@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //2.在Mp拦截器中添加具体的拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mpInterceptor;
    }
}

② 测试分页功能

    @Test
    void testGetByPage(){
        IPage page = new Page(1,2);
        userDao.selectPage(page,null);
        System.out.println("当前页码值:" + page.getCurrent());
        System.out.println("每页显示数:" + page.getSize());
        System.out.println("一共多少页:" + page.getPages());
        System.out.println("一共多少条数据:" + page.getTotal());
        System.out.println("数据:" + page.getRecords());
    }

开启日志

# 开启mp的日志(输出到控制台的日志)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.DQL编程控制

3.1 条件查询

MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合

关闭系统日志显示
resources包下创建logback.xml文件


<configuration>
configuration>

修改配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://192.168.1.224:3306/mybatisplus_db
    username: root
    password: 123456
  main:
    banner-mode: off

# 开启mp的日志(输出到控制台的日志)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: false

条件查询示例

    @Test
    void testGetAll(){
       //方式一:按条件查询
//        QueryWrapper qw = new QueryWrapper();
//        qw.lt("age",18);
//        List userList = userDao.selectList(qw);
//        System.out.println(userList);

        //方式二:lambda格式按条件查询
//        QueryWrapper qw = new QueryWrapper<>();
//        qw.lambda().lt(User::getAge,18);
//        List userList = userDao.selectList(qw);
//        System.out.println(userList);

        //方式三:lambda格式按条件查询
//        LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
//        lqw.lt(User::getAge,18);
//        List userList = userDao.selectList(lqw);
//        System.out.println(userList);

        //多条件
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //18到50之间
//        lqw.lt(User::getAge,50);
//        lqw.gt(User::getAge,18);
        //链式编程
//        lqw.lt(User::getAge,50).gt(User::getAge,18);
        //小于10岁或者大于18岁
        lqw.lt(User::getAge,10).or().gt(User::getAge,18);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    }

3.1.1 null值处理

用于限定age的上限

package com.example.domain.query;

import com.example.domain.User;
import lombok.Data;

@Data
public class UserQuery extends User {
    private Integer age2;
}

测试

    @Test
    void testGetAll2() {
        //模拟页面传递过来的查询数据
        UserQuery uq = new UserQuery();
        uq.setAge(10);
//        uq.setAge2(30);
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //先判定第一个条件是否为true,如果为true连接当前条件
        lqw.lt(null != uq.getAge2(),User::getAge,uq.getAge2())
                .gt(null != uq.getAge(),User::getAge,uq.getAge());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    }

3.2 查询投影

    @Test
    void testGetAll3() {
        //查询投影
//        LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
//        lqw.select(User::getId,User::getName,User::getAge);
        QueryWrapper lqw = new QueryWrapper<>();
        lqw.select("id","name","age");
//        List userList = userDao.selectList(lqw);
//        System.out.println(userList);

        QueryWrapper<User> lqw = new QueryWrapper<>();
        lqw.select("count(*) as count,tel")
                .groupBy("tel");
        List<Map<String,Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);
    }

3.3 查询条件

https://baomidou.com/pages/10c804/
查询条件在 核心功能 的 条件构造器 中查找

    @Test
    void testGetAll4() {
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        //等同于=
//        lqw.eq(User::getName,"Jerry")
//                .eq(User::getPassword,"jerry");
//        User user = userDao.selectOne(lqw);
//        System.out.println(user);

        //范围发查询lt le gt ge between
//        lqw.between(User::getAge,10,30);
//        List userList = userDao.selectList(lqw);
//        System.out.println(userList);

        //模糊匹配
        lqw.like(User::getName,"J");
//        lqw.likeRight(User::getName,"J");
//        lqw.likeLeft(User::getName,"J");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);
    }

3.4 字段映射与表名映射

1.问题一:表字段与编码属性设计不同步
@TableField:设置当前属性对应的数据库表中的字段关系

public class User {
    @TableField(value = "pwd")
    private String password;
}

2.问题二:编码中添加了数据库中未定义的属性

public class User {
    @TableField(exist = "false")
    private Integer online;
}

3.问题三:采用默认查询开放了更多的字段查询权限

public class User {
    @TableField(value = "pwd",select = false)
    private String password;
}

4.问题四:表名与编码开发设计不同步
@TableName:设置当前类对应于数据库表关系

@TableName("tbl_user")
public class User {
    @TableField(value = "pwd",select = false)
    private String password;
}

4.DML编程控制

4.1 id生成策略控制

不同的表应用不同的id生成策略
1.日志:自增(1,2,3,4,……)
2.购物订单:特殊规则(FQ23948AK3843)
3.外卖单:关联地区日期等信息(10 04 20200314 34 91)
4.关系表:可省略id

@TableId:设置当前类中主键属性的生成策略

public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
}
  • AUTO(0):使用数据库id自增策略控制id生成
  • NONE(1): 不设置id生成策略
  • INPUT(2):用户手工输入id
  • ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
  • ASSIGN_UUID(4):以UUID生成算法作为id生成策略

全局配置

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: false
    db-config:
      #id自增策略
      id-type: assign_id
      #表名前缀
      table-prefix: tbl_

4.2 多数据操作(删除)

添加和多数据删除

    @Test
    void testInsert(){
        User user = new User();
        user.setAge(11);
        user.setName("小王");
        user.setPassword("xiaowang");
        user.setTel("123456");
        User user1 = new User();
        user1.setAge(12);
        user1.setName("小华");
        user1.setPassword("xiaohua");
        user1.setTel("1234568");
        userDao.insert(user);
        userDao.insert(user1);
    }

    @Test
    void testDelete(){
        List<Long> list = new ArrayList<>();
        list.add(1530525838229913601L);
        list.add(1530525929594437633L);
        userDao.deleteBatchIds(list);

//        List list = new ArrayList<>();
//        list.add(1L);
//        list.add(2L);
//        userDao.selectBatchIds(list);
    }

逻辑删除
删除业务问题:业务数据从数据库中丢弃
逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中。

mysql的user表添加一个delete字段(int,长度为1,默认值为0)

User中添加逻辑删除字段的属性

package com.example.domain;

import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.*;

@Data
public class User {
//    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
    //逻辑删除字段,标记当前是否被删除
    @TableLogic(value = "0",delval = "1")
    private Integer deleted;
}

进行逻辑删除

    @Test
    void testDelete(){
        userDao.deleteById(1L);
    }

全局配置代替注解

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0

4.3 乐观锁

① 给user添加字段version(int,长度11,默认值1)
② 在实体类中添加属性和注解

package com.example.domain;

import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.*;

@Data
public class User {
//    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
    //逻辑删除字段,标记当前是否被删除
//    @TableLogic(value = "0",delval = "1")
    private Integer deleted;
    @Version
    private Integer version;
}

③ 添加乐观锁的拦截器

package com.example.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //2.在Mp拦截器中添加具体的拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        //3.添加乐观锁的拦截器
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mpInterceptor;
    }
}

④ 测试

    @Test
    void testUpdate(){
//        User user = new User();
//        user.setId(3L);
//        user.setName("Jock666");
//        user.setVersion(1);
//        userDao.updateById(user);

        //1.先通过要修改的数据id将当前数据查询出来
        User user = userDao.selectById(3L); //version=3
        User user2 = userDao.selectById(3L);//version=3

        //2.将要修改的属性逐一设置进去
        user2.setName("Jock999");
        userDao.updateById(user2);//version=4

        user.setName("Jock888");
        userDao.updateById(user);//version不等于3,失效
    }

5.代码生成器

模板:MyBatisPlus提供
数据库相关配置:读取数据库获取信息
开发者自定义配置:手工配置

① 添加依赖坐标


<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-generatorartifactId>
    <version>3.4.1version>
dependency>

<dependency>
    <groupId>org.apache.velocitygroupId>
    <artifactId>velocity-engine-coreartifactId>
    <version>2.3version>
dependency>

② 代码生成器

package com.example;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;

public class Generator {
    public static void main(String[] args) {
        //1.获取代码生成器的对象
        AutoGenerator autoGenerator = new AutoGenerator();

        //设置数据库相关配置
        DataSourceConfig datasource = new DataSourceConfig();
        datasource.setDriverName("com.mysql.cj.jdbc.Driver");
        datasource.setUrl("jdbc:mysql://192.168.1.224:3306/mybatisplus_db");
        datasource.setUsername("root");
        datasource.setPassword("123456");
        autoGenerator.setDataSource(datasource);

        //设置全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");    //设置代码生成位置
        globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setAuthor("www");    //设置作者
        globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件
        globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
        globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
        autoGenerator.setGlobalConfig(globalConfig);

        //设置包名相关配置
        PackageConfig packageInfo = new PackageConfig();
        packageInfo.setParent("com.test");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        packageInfo.setEntity("domain");    //设置实体类包名
        packageInfo.setMapper("dao");   //设置数据层包名
        autoGenerator.setPackageInfo(packageInfo);

        //策略设置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("user");  //设置当前参与生成的表名,参数为可变参数
        strategyConfig.setTablePrefix("");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
        strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格
        strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
        strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
        strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
        autoGenerator.setStrategy(strategyConfig);

        //2.执行生成操作
        autoGenerator.execute();
    }
}

你可能感兴趣的:(java,mysql,intellij-idea)