Mybatisplus学习笔记

1、Mybatisplus

MP是基于Mybatis框架基础上开发的增强型工具,旨在简化开发、提高效率!

入门案例:

  • Springboot整合mybatis开发—复习

    • 创建SpringBoot工程

    • 勾选配置使用的技术

    • 设置dataSource相关属性(DBC参数)

    • 定义数据层接口映射配置

1、导入起步依赖

创建项目的时候只要web和mysql,不需要mybatis,因为导入mybatis-plus里边会自动有一些基础的包。

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

2、配置yml,设置jdbc参数

spring:
  datasource:
    username: root
    password: 123
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/user?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

3、创建entity

package com.yang.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private String pwd;
    private Integer age;
    private String tel;
}

4、创建dao

// 定义数据接口,继承BaseMapper<User> !!!
@Mapper
public interface UserDao extends BaseMapper<User> {
    
}

5、测试

package com.yang;
@SpringBootTest
class Springboot12MybatisplusApplicationTests {
    @Autowired
    private UserDao userDao;

    @Test
    void contextLoads() {
        List<User> users = userDao.selectList(null);
        // 遍历list
        for (User s : users) {
            System.out.println(s);
        }
    }

}

2、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 操作智能分析阻断,也可自定义拦截规则,预防误操作

3、标准CRUD操作

1、标准数据层CRUD功能

2、测试

package com.yang;
@SpringBootTest
class Springboot12MybatisplusApplicationTests {

    @Autowired
    private UserDao userDao;

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

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

    @Test
    void testAdd(){
        User user = new User();
        user.setId(7L);
        user.setName("POOP");
        user.setPassword("123456789");
        user.setAge(18);
        user.setTel("115588988774");
        userDao.insert(user);
    }

    @Test
    void testUpdate(){
        User user = new User();
        user.setId(7L); // 修改哪个id用户的属性!
        user.setName("Pool");
        user.setTel("18155455695");
        userDao.updateById(user);
    }

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

}

4、标准分页功能制作

分页查询 – 复习

limit start, size 的含义:start是表示起始数据的行数、size表示展示的数据数量

特别需要注意的是MySQL中的第一条数据是从下标index = 0开始算的。例如:查询工资的前1-5名,和工资的2-6名。

-- 前1-5名
select name, sal from emp order by sal desc  limit 0, 5

-- 前2-6名
select name, sal from emp order by sal desc  limit 1, 5

limit [start], size中的start可以不写,如果不写等价于start = 0,size 表示需要展示的数据条数。

查询第k名(升序、逆序)时聚合函数似乎显得力不从心了,这时候可以使用order by 排序 + limit 进行一下挑选。

查询某个字段第k名的数据。注意是k-1(从0开始!)
select * from 表名 order by 字段 desc/asc limit k-1, 1

Mp实现分页查询:

1、配置分页拦截器

@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor(){
        // 1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        // 2.添加具体的拦截器
        // 添加分页拦截器,如果不添加,则无法实现mp的分页,添加即可使用
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mpInterceptor;
    }
}

2、测试

@Test
    void testGetByPage(){
        // 1代表你查第几页,2代表每页查几条
        IPage page = new Page(1,2);
        userDao.selectPage(page,null);
        System.out.println("当前页码值:" + page.getCurrent());       // 1
        System.out.println("每页显示数:" + page.getSize());          // 2
        System.out.println("一共多少页:" + page.getPages());         // 4
        System.out.println("一共多少条数据:" + page.getTotal());      // 7
        System.out.println("数据:" + page.getRecords());
        // 数据:[User(id=1, name=Tom, password=123, age=3, tel=16855655632), 
        //       User(id=2, name=Jac, password=123, age=13, tel=12223232323)]
    }

3、配置MybatisPlus的运行日志:(调程序用的,一般可以不开启!)

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

5、条件查询的三种格式

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

所有带Wrapper queryWrapper的都是可以添加条件的。

在这里插入图片描述

取消控制台的所有日志打印,看着更加简单! 在Resources下创建logback.xml文件。

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
</configuration>

Mybatis-plus中sql语句LT、LE、EQ、NE、GE、GT的意思:

  • lt:less than 小于
  • le:less than or equal to 小于等于
  • eq:equal to 等于
  • ne:not equal to 不等于
  • ge:greater than or equal to 大于等于
  • gt:greater than 大于

QueryWrapper条件构造器

queryWrapper.lt()——小于
queryWrapper.le()——小于等于
queryWrapper.gt()——大于
queryWrapper.ge()——大于等于
queryWrapper.eq()——等于
queryWrapper.ne()——不等于
queryWrapper.betweeen(“age”,10,20)——age在值10到20之间
queryWrapper.notBetweeen(“age”,10,20)——age不在值10到20之间
queryWrapper.like(“属性” , “值”)——模糊查询匹配值‘%值%’
queryWrapper.notLike(“属性” , “值”)——模糊查询不匹配值‘%值%’
queryWrapper.likeLeft(“属性”,“值”)——模糊查询匹配最后一位值‘%值’
queryWrapper.likeRight(“属性”,“值”)——模糊查询匹配第一位值‘值%’
queryWrapper.isNull()——值为空或null
queryWrapper.isNotNull()——值不为空或null
queryWrapper.in(“属性”,条件,条件 )——符合多个条件的值
queryWrapper.notIn(“属性”,条件,条件 )——不符合多个条件的值
queryWrapper.or()——或者
queryWrapper.and()——和
queryWrapper.orderByAsc(“属性”)——根据属性升序排序
queryWrapper.orderByDesc(“属性”)——根据属性降序排序
queryWrapper.inSql(“sql语句”)——符合sql语句的值
queryWrapper.notSql(“sql语句”)——不符合SQL语句的值
queryWrapper.esists(“SQL语句”)——查询符合SQL语句的值
queryWrapper.notEsists(“SQL语句”)——查询不符合SQL语句的值

    @Test
    void testGetAll() {
        // 第一种方式:按条件查询
        QueryWrapper qw = new QueryWrapper();
        // 添加条件年龄小于18
        qw.lt("age",18);
        List<User> users = userDao.selectList(qw);
        users.forEach(System.out::println);

        // 第二种方式:按条件查询
        QueryWrapper<User> qw = new QueryWrapper<User>();
        // 添加条件年龄小于18
        // User::getAge,为lambda表达式中的,类名::方法名
        qw.lambda().lt(User::getAge,18);
        List<User> users = userDao.selectList(qw);
        users.forEach(System.out::println);

        // 第三种方式:按条件查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.lt(User::getAge,18);
        lqw.gt(User::getAge,18);
        // 上边两条代码可以写成链式编程
        // lqw.lt(User::getAge,30).gt(User::getAge,18);
        List<User> users = userDao.selectList(lqw);
        users.forEach(System.out::println);

    }

组合条件

​ 并且关系(and)

//并且关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//并且关系:10到30岁之间
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);

​ 或者关系(or)

//或者关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//或者关系:小于10岁或者大于30岁
lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);

6、条件查询NULL判空

遇到条件查询,记得添加空值判定!!!

// 模拟页面传递过来的数据
UserQuery uq = new UserQuery();
uq.setAge(10);
uq.setAge2(30);

// null判定
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.lt(null != uq.getAge2(),User::getAge,uq.getAge2());
lqw.gt(null != uq.getAge(),User::getAge,uq.getAge());
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);

7、查询投影

通俗来讲就是设置查询出来的结果长什么样! 查询字段控制!

//  LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
//  lqw.select(User::getId,User::getName,User::getAge);
	QueryWrapper<User> qw = new QueryWrapper<>();
	qw.select("id","name","age","tel");	// 限制只输出这几个字段!
	//qw.select("id,name,age,tel");		// 相同的效果
	List<User> users = userDao.selectList(qw);
	users.forEach(System.out::println);

// 统计报表(分组查询聚合函数) groupBy  
	QueryWrapper<User> qw = new QueryWrapper<>();
    qw.select("count(*) as count , age");
    // 按age分组
    qw.groupBy("age");
    List<Map<String, Object>> users = userDao.selectMaps(qw);
    users.forEach(System.out::println);
    // 输出{每个年龄的个数 + 年龄}的集合

8、查询条件设置

  • 范围匹配 (>、= 、 between )
  • 模糊匹配 (like)
  • 空判定(null)
  • 包含性匹配 (in)
  • 分组(group)
  • 排序(order)
// 条件查询 eq
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
// 相当于=
lqw.eq(User::getName,"Tom").eq(User::getPassword,"123");
User user = userDao.selectOne(lqw);
System.out.println(user);
// 条件查询 between
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
// 查询年龄在18-30之间的 , 严格前边参数小,后边大
lqw.between(User::getAge,18,30);
List<User> users = userDao.selectList(lqw);
System.out.println(users);
// 条件查询 -- 查信息,搜索新闻(非全文检索版:like匹配)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();

// 条件查询带有P的名字  ==>  %P%
lqw.like(User::getName,"P");
// 条件查询以P开头的名字 ==>  P%
lqw.likeRight(User::getName,"P")
// 条件查询以P结尾的名字  ==> %P
lqw.likeLeft(User::getName,"P");

List<User> users = userDao.selectList(lqw);
System.out.println(users);

https://baomidou.com/pages/10c804/#isnull

查看官方文档查看更多 条件构造器 的方法!!

9、映射匹配兼容性

字段映射 与 表明映射

问题一 、如果数据库字段 和 实体类中的属性名不一样时怎么办??? 一般修改代码中的属性名!!!

方法 :使用 @TableField (value=“”)

  • 名称:@TableField

  • 类型:属性注解

  • 位置:模型类属性定义上方

  • 作用:设置当前属性对应的数据库表中的字段关系

  • 例如

    public class User {
    	@TableField(value="pwd")
    	private String password;
    }
    
  • 相关属性

    • value(默认):设置数据库字段名
    • exist: 设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用
    • select:设置属性是否参与查询,此属性与select() 映射配置不冲突

问题二、实体类中添加了数据库中未定义的属性

方法:使用 @TableField(exist = false)

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

问题三、采用默认查询开放了更多的字段查看权限!

比如:我们查询用户信息的时候,不能把密码查询输出

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

问题四、表名与编码开发设计不同步

方法 :使用 @TableName(“tb1_User”) 注解类

CREATE TABLE `tb1_user`(
    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    `name` varchar(32),
    `pwd` varchar(32),
    `age` int(3),
    `tel` varchar(32),
    PRIMARY KEY (`id`)
)
@TableName("tbl_user")   // 相当于做了个映射关系,实体类名称和表名做了个绑定
public class User {
    private Long id;
    private string name;
    @TableField(value=" pwd" ,select = false)
    private String password;
    private Integer age;
    private string tel;
    @TableField(exist = false)
    private Integer online;
}

10、id生成策略控制

	@TableId(type = IdType.AUTO)  // 自增
    private Long id;
    @TableId(type = IdType.INPUT)  // 需要用户自行输入
    private Long id;
    @TableId(type = IdType.ASSIGN_ID)	// 自动生成Id 如果自己设置了就是自己设置的,如果没有设置则是自动生成的
    private Long id;
  • AUTO(0):使用数据库id自增策略控制id生成
  • NONE(1)︰不设置id生成策略
  • INPUT(2)︰用户手工输入id
  • ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
  • ASSIGN_UUID(4):以UUID生成算法作为id生成策略

但是,这样配置每个属性上一个注解,这样显的很臃肿,可以在yml上进行设置。

mybatis-plus:
  global-config:
    db-config:
      # id自增
      id-type: auto
      # 每一个实体类上就不用写@TableNmae()了,相当于拼接tb_
      table-prefix: tb_

11、多数据操作(删除和查询)

@Test
void testBatch(){
    List<Long> list = new ArrayList<>();
    list.add(1L);
    list.add(2L);
    // 按照主键删除多条记录
    // userDao.deleteBatchIds(list);
    
    // 按照主键查询多条数据
    userDao.selectBatchIds(list);
}

12、逻辑删除

删除操作业务问题:业务数据从数据库中丢弃

逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据仍保存在数据库中
在这里插入图片描述

1、 数据库添加deleted字段(默认为0),实体类添加deleted属性

// 逻辑删除字段,标记当前记录是否被删除 0没删除,1代表删除
@TableLogic(value = "0", delval = "1")
private Integer deleted;

2、 测试删除

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

控制台:可以看出删除操作变成了更新操作!

==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
> Parameters: 6(Long)
<
Updates: 1

3、测试:查询

@Test
void testGetAll() {
    // 条件查询
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
    List<User> users = userDao.selectList(lqw);
    System.out.println(users);
}

查询结果没有6号用户(只有deleted字段为0的)

注意:

​ 以上注解@TableLogic(value = “0”, delval = “1”)也可以写成配置的形式

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted	# 设置逻辑删除的字段名
      logic-delete-value: 1			# 删除了的字段为1
      logic-not-delete-value: 0		# 没有删除的字段为0

13、乐观锁

锁是用来解决并发问题的!(并发操作:是指同一时间可能有多个用户对同一数据进行读写操作)

MP是如何实现锁?一般只能处理2000请求量以下,只能满足小企业开发中的情形。

1、数据库添加version字段 (默认为1) ,实体类添加version属性

@Version
private Integer version;

2、添加乐观锁的拦截器

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

3、测试

@Test
void testOptLock(){
    // 1、先按id查询出要修改的用户
    User user = userDao.selectById(5L);
    User user2 = userDao.selectById(5L);

    // 2、模拟两个用户同时修改name属性
    user.setName("Jac 111");
    userDao.updateById(user);

    user2.setName("Jac 222");
    userDao.updateById(user2);
}

​ 前一个用户更新完操作会修改version的值为2,

​ 第二个用户获取到version就不是1了 所以不能查询成功!

在这里插入图片描述

14、代码生成器 – 快速开发

  • 模板:MyBatisPlus提供
  • 数据库相关配置:读取数据库获取信息
  • 开发者自定义配置:手工配置
<!--mybatis plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>
<!--代码生成器-->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generate</artifactId>
	<version>2.3</version>
</dependency>

<!--velocity模板引擎-->
<dependency>
	<groupId>org.apache.velocity</groupId>
	<artifactId>velocity-engine-core</artifactId>
	<version>2.0</version>
</dependency>
package com.yang;

import com.baomidou.mybatisplus.enums.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;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

public class Generator {
    public static void main(String[] args) {
        // 1、创建代码生成器对象
        AutoGenerator autoGenerator = new AutoGenerator();

        // 2、数据源配置
        DataSourceConfig dataSource = new DataSourceConfig();
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/user?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("123");
        autoGenerator.setDataSource(dataSource);

        // 3、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("yang");               //设置作者
        gc.setOpen(true);                   //生成后是否打开资源管理器
        gc.setFileOverride(false);          //重新生成时文件是否覆盖
        gc.setServiceName("%sService");	    //去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER);     //主键策略
        autoGenerator.setGlobalConfig(gc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.generator");       // 设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        autoGenerator.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        //strategy.setInclude("user","teacher");               // 设置当前参与生成的表名,参数为可变参数,可以多个!
        //strategy.setTablePrefix("tbl_");                     // 生成实体时去掉表前缀
        //strategy.setNaming(NamingStrategy.underline_to_camel);  // 数据库表映射到实体的命名策略
        //strategy.setColumnNaming(NamingStrategy.underline_to_camel);    //数据库表字段映射到实体的命名策略
        strategy.setRestControllerStyle(true);                  // restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true);         // url中驼峰转连字符
        strategy.setEntityLombokModel(true);                    // 设置entity是否启用Lombok

        //strategy.setLogicDeleteFieldName("deleted");            // 设置逻辑删除字段名
        //strategy.setVersionFieldName("version");                // 设置乐观锁字段名
        autoGenerator.setStrategy(strategy);

        // 6、执行
        autoGenerator.execute();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值