当前位置: 首页 > news >正文

七、Java框架之MyBatisPlus

黑马课程

文章目录

  • 1. MyBatisPlus入门
    • 1.1 MyBatisPlus入门案例
      • 步骤1:创建spring boot工程
      • 步骤2:配置application.yml
      • 步骤3:创建数据库表(重点)
      • 步骤4:编写dao层
      • 步骤5:测试
    • 1.2 标准数据层开发
      • 标准CRDU使用
      • Lombok
      • 分页功能
      • 配置MP运行日志
  • 2. DQL编程控制 —— 查
    • 2.1 条件查询的三种方式
    • 2.2 多条件查询
    • 2.3 null值处理
    • 2.4 查询投影
    • 2.5 查询条件
      • 环境准备
      • 等值查询
      • 范围查询
      • 模糊匹配
      • 排序查询
    • 2.6 映射匹配兼容性
      • 表名与编码开发设计不同步
      • 表字段与编码属性设计不同步
      • 编码中添加了数据库中未定义的属性
      • 特殊字段不参与查询,如password
  • 3. DML编程控制 —— 增删改
    • 3.1 新增 —— id生成策略
    • 3.2 删除
      • 多记录删除
      • 逻辑删除 @TableLogic
      • 逻辑删除 配置文件方式
    • 3.3 修改 —— 乐观锁
  • 4. 代码生成器
    • 4.1 代码生成器实现
      • 步骤1:导入坐标
      • 步骤2:编写代码生成器
      • 步骤3:测试生成的类

1. MyBatisPlus入门

  • MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提供效率

  • 开发方式

    • 基于MyBatis使用MyBatisPlus
    • 基于Spring使用MyBatisPlus
    • 基于SpringBoot使用MyBatisPlus

1.1 MyBatisPlus入门案例

和MyBatis进行比较

步骤1:创建spring boot工程

在选择依赖处,勾选Web/Spring WebSQL/MySQL Driver

  • 注意:这里没有再勾选SQL/MyBatis Framework,这是因为MP并未被收录到idea的系统内置配置,无法直接选择加入,需要手动在pom.xml中配置添加

pom.xml中依赖如下

<dependencies><!-- 自动生成 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 需手动添加 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency>
</dependencies>
  • mybatis-plus-boot-starter就导入了mybatis相关坐标,以及spring整合mybatis相关坐标

步骤2:配置application.yml

删除原有的application.properties,新建application.yml

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?useSSL=false&serverTimezone=UTCusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSources

步骤3:创建数据库表(重点)

在之前的项目中,数据库表的表名没有要求
在MyBatisPlus中,数据库表名一定要和domain中的实体类类名相对应!

  • 例如:实体类名为Book,那么数据库表名就应该是book

  • id类型应当为 bigint(20)

    alter table book modify id bigint(20);
    
  • 对应的Book实体类的id也应该是 Long 类型

步骤4:编写dao层

package com.example.dao;@Mapper
public interface BookDao extends BaseMapper<Book> {
}
  • 只需要继承 BaseMapper<Book>,无需写SQL注解

步骤5:测试

package com.example;@SpringBootTest
class MybatisplusApplicationTests {@Autowiredprivate BookDao bookDao;@Testvoid testGetAll(){List<Book> bookList = bookDao.selectList(null);System.out.println(bookList);}
}
  • 即便BookDao里面没有写方法,但使用bookDao时,依然会发现许多方法可供使用
  • MP提供了默认的一些简单的增删改查方法,从而无需自己编写

1.2 标准数据层开发

标准CRDU使用

在这里插入图片描述

package com.example.dao;@Mapper
public interface BookDao extends BaseMapper<Book> {
}
package com.example;@SpringBootTest
class MybatisplusApplicationTests {@Autowiredprivate BookDao bookDao;@Testvoid testSave(){Book book = new Book();book.setType("kk");book.setName("kk");book.setDescription("kk");bookDao.insert(book);}@Testvoid testDelete(){bookDao.deleteById(1619646956185972738L);}@Testvoid testUpdate(){Book book = new Book();book.setId(1L);book.setType("kk2");bookDao.updateById(book);}@Testvoid testGetById(){Book book = bookDao.selectById(1L);System.out.println(book);}@Testvoid testGetAll(){List<Book> bookList = bookDao.selectList(null);System.out.println(bookList);}}

Lombok

一个Java类库,提供了一组注解,简化POJO实体类开发

步骤1:导入jar包

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version>
</dependency>

报错的话,加上版本号;否则不加

步骤2:在实体类上加上注解

在之前都是需要手动添加getter, setter, toString等方法,现在可以用以下注解替代

package com.example.domain;@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//自动生成hashCode
public class Book {private Long id;private String name;private String type;private String description;
}

更进一步,可以简化成

package com.example.domain;@Data
public class Book {private Long id;private String name;private String type;private String description;
}
  • @Data包含除构造器外的其他方法

分页功能

步骤1:编写拦截器

拦截器MP已经提供,只需要将其配置成Spring管理的bean对象即可

package com.example.config;@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor mpInterceptor(){//1. 定义MP拦截器MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();//2. 添加具体的拦截器mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mpInterceptor;}
}

步骤2:分页查询

分页查询使用的方法是:

IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper)
  • IPage:用来构建分页查询条件,第几页,一页多少行
  • Wrapper:用来构建条件查询的条件,目前我们没有可直接传为Null
  • IPage:返回值,构建分页条件和方法的返回值都是IPage
@Test
void testGetByPage(){IPage page = new Page(1, 5);//查询第1页,每页10行bookDao.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运行日志

application.yml中增加

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

此时有很多日志输出,但许多暂时用不到,需要将其删除,此时可以新建一个 logback.xml,如下

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

一些日志已经不再显示,现在取消MybatisPlus启动banner图标,在application.yml中增加内容如下

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

还剩下springboot的banner,如果需要将其删除,在 application.yml 中配置如下

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/ssm_db?useSSL=false&serverTimeZone=UTCusername: rootpassword: 123456type: com.alibaba.druid.pool.DruidDataSourcemain:banner-mode: off#开启MP的日志(输出到控制台)
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplglobal-config:banner: false

2. DQL编程控制 —— 查

bookDao.selectList(null) 查看selectList源码,发现它需要一个Wrapper<T>的参数
查看wrapper<T>,发现其为一个抽象类

public abstract class Wrapper<T> implements ISqlSegment {...}

ctrl+h 查看其继承类

在这里插入图片描述

其中 QueryWrapper 即是需要的实现类

2.1 条件查询的三种方式

//查询 id<6 的数据
@Test
void testGetAll(){//方式一:按条件查询QueryWrapper qw = new QueryWrapper();qw.lt("id", 6);//方式二:lambda格式按条件查询QueryWrapper<Book> qw = new QueryWrapper<Book>();qw.lambda().lt(Book::getId, 6);//方式三(推荐):lambda格式按条件查询LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();lqw.lt(Book::getId, 6);List<Book> bookList = bookDao.selectList(lqw);System.out.println(bookList);
}

2.2 多条件查询

  • and 查询

    //查询 id>6 但 <10的数据
    lqw.gt(Book::getId, 6).lt(Book::getId, 10);
    

    或者

    lqw.gt(Book::getId, 6);
    lqw.lt(Book::getId, 10);
    
  • or 查询

    //查询 id<3 或者 id>10的数据
    lqw.lt(Book::getId, 3).or().gt(Book::getId, 10);
    

2.3 null值处理

//模拟页面传递过来的查询数据:查询 5<id<10的数据
Long idMin = null;
Long idMax = 10L;LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
//null判断:先判定是否为null,如果为null,就不连接
lqw.lt(null != idMax, Book::getId, idMax);
lqw.gt(null != idMin, Book::getId, idMin);List<Book> bookList = bookDao.selectList(lqw);
System.out.println(bookList);

2.4 查询投影

  • 查询指定字段

    //查询投影:只适应lambda的格式
    LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
    lqw.select(Book::getId, Book::getName, Book::getType);
    List<Book> bookList = bookDao.selectList(lqw);//查询投影:非lambda的格式
    QueryWrapper<Book> qw = new QueryWrapper<Book>();
    qw.select("id", "name", "type");
    List<Book> bookList = bookDao.selectList(qw);
    
  • 聚合查询

    完成count、max、min、avg、sum的使用

    @Test
    void testGetAll(){QueryWrapper<Book> qw = new QueryWrapper<Book>();//1. 计算总记录数qw.select("count(*) as count, type");//2. 按type分组qw.groupBy("type");//3. 获取数据List<Map<String, Object>> bookList = bookDao.selectMaps(qw);System.out.println(bookList);
    }
    

    在这里插入图片描述

当MyBatisPlus无法处理需要的SQL要求时,仍然可以在bookDao中按老方法进行编写

2.5 查询条件

其他条件查询使用方法可以去官网的指南上查询:https://baomidou.com/

环境准备

准备:user数据库表,User类等

数据库表

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,'玛丽','123456',15,'4006184000');

User实体类

package com.example.domain;@Data
public class User {private Long id;private String name;private String password;private int age;private String tel;
}

UserDao

package com.example.dao;@Mapper
public interface UserDao extends BaseMapper<User> {
}

等值查询

需求:根据用户名和密码查询用户信息

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.eq(User::getName, "玛丽").eq(User::getPassword, "123456");//实际中密码需要md5加密
User user = userDao.selectOne(lqw);

范围查询

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.between(User::getAge, 10, 50);
List<User> userList = userDao.selectList(lqw);

模糊匹配

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.like(User::getName, "J");//匹配 %J%
lqw.likeLeft(User::getName, "J");//匹配 %J
lqw.likeRight(User::getName, "J");//匹配 J%
List<User> userList = userDao.selectList(lqw);
  • like():前后加百分号,如 %J%
  • likeLeft():前面加百分号,如 %J
  • likeRight():后面加百分号,如 J%

排序查询

需求:查询所有数据,然后按照id降序

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
/*** condition :条件,返回boolean,当condition为true,进行排序,如果为false,则不排序* isAsc:是否为升序,true为升序,false为降序* columns:需要操作的列* 下面表示,进行排序,升序,排序字段是age*/
lqw.orderBy(true, true, User::getAge);
List<User> userList = userDao.selectList(lqw);

2.6 映射匹配兼容性

表名与编码开发设计不同步

  • 准备:将数据库表user修改为 tbl_user,以进行演示

    alter table user rename to tbl_user;
    

    此时数据库表名为tbl_user,实体类为User,MP将不能正确识别

  • 只需要在User实体类上添加@TableName注解即可

@Data
@TableName("tbl_user")
public class User {private Long id;private String name;private String password;private int age;private String tel;
}

如果希望对所有实体类都进行这样的替换,可以用全局配置替换@TableName

#替换所有实体类对应的表名
mybatis-plus:global-config:db-config:table-prefix: tbl_user

表字段与编码属性设计不同步

  • 准备:将数据库表tbl_user中的字段password改为pwd

    alter table user change password pwd varchar(32) not null;
    
  • 只需要在User实体类对应字段加上@TableField注解即可

此时数据库表名为tbl_user,实体类为User,MP将不能正确识别

@Data
public class User {private Long id;private String name;@TableField(value = "pwd")private String password;private int age;private String tel;
}

编码中添加了数据库中未定义的属性

例如:在插入数据时,User实体类中有一个online属性,但数据库表user中没有这个字段,此时将报错,解决方法如下

@TableField(exist = false)

@Data
public class User {private Long id;private String name;private String password;private int age;private String tel;@TableField(exist = false)private Integer online;
}

特殊字段不参与查询,如password

password将不参与查询,需要隐藏起来

@Data
public class User {private Long id;private String name;@TableField(value = "pwd", select = false)private String password;private int age;private String tel;
}

这样设置后,查询后password字段将为空

3. DML编程控制 —— 增删改

3.1 新增 —— id生成策略

@Data
public class User {@TableId(type = IdType.AUTO)private Long id;
}

如果希望设置所有实体类的id生成策略,需要在application.yml文件中配置

#设置id生成策略
mybatis-plus:global-config:db-config:id-type: assign_id

IdType有以下几种

  • Auto:数据库id自增
  • NONE:不设置id生成策略
  • INPUT:用户手工输入id
  • ASSIGN_ID(默认):雪花算法生成id(可兼容数值型与字符串型)
  • ASSIGN_UUID:以UUID生成算法作为id生成策略
  • 其他的几个策略 ID_WORKER, ID_WORKER_STR, UUID 均已过时,都将被ASSIGN_ID和ASSIGN_UUID代替掉。

雪花算法

生成一个64位的二进制数字,及Long的大小

在这里插入图片描述

  • 1bit,不用,因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0

  • 41bit-时间戳,用来记录时间戳,毫秒级

  • 10bit-工作机器id,用来记录工作机器id,其中高位5bit是数据中心ID,其取值范围0-31
    低位5bit是工作节点ID,其取值范围0-31,两个组合起来最多可以容纳1024个节点

  • 序列号占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID

3.2 删除

多记录删除

deleteBatchIds

List<Long> list = new ArrayList<>();
list.add(1619725419349172225L);
list.add(6L);
list.add(5L);
userDao.deleteBatchIds(list);

同理,也可以多数据查询:selectBatchIds

逻辑删除 @TableLogic

场景
人员表:删除了人员zhangsan
订单表:zhangsan对应的订单order1,order2成为脏数据,或者跟着一起被删除,因此无法被读取
结果:之后年度汇总,发现订单数量对不上
解决方案:逻辑标记

逻辑删除

为数据设置是否可用状态字段 deleted,删除时设置状态字段为不可用状态,数据保留在数据库中,执行的是update操作

  • 使用 @TableLogic注解 标注 删除标识字段
  • 设置了标识字段也不会影响 select 语句,因此此后在查询时会自动添加如 where selected=0
  • 如果设置了标识字段,又想看到已被删除的数据,那么需要自己写sql语句

步骤1:为数据库表增加逻辑删除字段 deleted,设置默认值为0,未删除

alter table user add deleted int default 0;

步骤2:在实体类User中增加删除标识字段deleted

@Data
public class User {private Long id;private String name;@TableField(select = false)private String password;private int age;private String tel;//增加删除字段:value表示未删除,delval表示已删除@TableLogic(value = "0", delval = "1")private Integer deleted;
}

步骤3:运行删除方法

userDao.deleteById(1L);

发现执行的是update语句,且数据库该条数据仍存在

在这里插入图片描述

逻辑删除 配置文件方式

在 User实体类 中添加删除字段

private Integer deleted;

在 application.yml 中配置

#配置删除字段
mybatis-plus:global-config:db-config:logic-delete-field: deletedlogic-not-delete-value: 0logic-delete-value: 1

3.3 修改 —— 乐观锁

这里的方案适用于小系统,并发在2000以下

  • 悲观锁:每次使用共享资源前先上锁
  • 乐观锁:通常是在表里加一个版本或时间戳,要更新前检查一下自己保存的版本和表现在的版本对比,如果不一样,说明被更改过了,于是通知操作者重新操作

步骤1:在数据库中增加列version,标记当前版本号

alter table user add version int default 1;

步骤2:在实体类中添加字段 version,并添加注解@Version

package com.example.domain;@Data
public class User {private Long id;private String name;@TableField(select = false)private String password;private int age;private String tel;//增加删除字段:value表示未删除,delval表示已删除@TableLogic(value = "0", delval = "1")private Integer deleted;//增加版本字段@Versionprivate Integer version;
}

步骤3:添加乐观锁的拦截器

package com.example.config;@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor mpInterceptor(){//1. 定义MP拦截器MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();//2. 添加之前的分页拦截器mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());//3. 添加乐观锁拦截器//作用:修改时,将在SQL语句中添加 set version=version+1mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mpInterceptor;}
}

步骤4:测试

//1. 通过要修改的数据id将当前的数据查询处理
User user = userDao.selectById(2L);
//2. 修改属性值
user.setName("Lili");
//3. 进行修改
userDao.updateById(user);

在执行前,表中该条数据的version是1,执行后version为2

  • 一定要获取数据,这样来获取到当前的版本号
  • 修改时,会将自己目前的版本号和数据库版本号比对,来判断在该条数据是否被修改过

步骤5:模拟并发情况

@Test
void testUpdate(){//1. user1和user2同时访问第1条数据User user1 = userDao.selectById(4L); //version = 1;User user2 = userDao.selectById(4L); //version = 1;//2. user2对第1条数据进行了修改user2.setName("user2");userDao.updateById(user2); //version = 2;//3. user1此时再对第1条数据进行修改:失败user1.setName("user1");userDao.updateById(user1);
}

user1更新失败,因为它的version=1,而数据库该条数据已经变为 version=2
此时,user1需要重新操作:再获取一次数据,然后再更新

4. 代码生成器

像是BookDao,UserDao,这些类都有相似的结构,可以抽取出来做成模板,这也就是代码生成器的原理

  • 模板:MyBatisPlus提供,可以自己提供,但是麻烦,不建议
  • 数据库相关配置:读取数据库获取表和字段信息
  • 开发者自定义配置:手工配置,比如ID生成策略

4.1 代码生成器实现

步骤1:导入坐标

<dependencies><!-- spring webmvc --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- mysql --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- mybatisplus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version></dependency><!-- druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency><!-- 代码生成器 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.4.1</version></dependency><!-- velocity模板引擎 --><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version></dependency>
</dependencies>

步骤2:编写代码生成器

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 CodeGenerator {public static void main(String[] args){//1. 定义一个自动生成器对象AutoGenerator autoGenerator = new AutoGenerator();//2. 设置数据源DataSourceConfig dataSource = new DataSourceConfig();dataSource.setDriverName("com.mysql.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/ssm_db?useSSL=false&serverTimezone=UTC");dataSource.setUsername("root");dataSource.setPassword("123456");autoGenerator.setDataSource(dataSource);//3. 设置全局配置GlobalConfig globalConfig = new GlobalConfig();globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");//设置生成的文件的位置为当前项目的java目录下globalConfig.setOpen(false);//设置生成完毕后是否打开生成代码所在的目录globalConfig.setAuthor("unknown");//设置作者globalConfig.setFileOverride(true);//设置是否覆盖原始生成的文件globalConfig.setMapperName("%sDao");//设置数据层接口名,%s为占位符,指代模块名称,默认为 %sMapperglobalConfig.setIdType(IdType.ASSIGN_ID);//设置Id生成策略autoGenerator.setGlobalConfig(globalConfig);//4. 设置包名相关配置PackageConfig packageConfig = new PackageConfig();packageConfig.setParent("com.example");//设置生成的包名,与setOutputDir的位置不冲突,二者叠加组成完整路径packageConfig.setEntity("domain");//设置实体类包名packageConfig.setMapper("dao");//设置数据层包名autoGenerator.setPackageInfo(packageConfig);//5. 策略配置(核心)StrategyConfig strategyConfig = new StrategyConfig();
//        strategyConfig.setInclude("tbl_table1", "tbl_table2");//生成指定的表(必须要存在)strategyConfig.setTablePrefix("tbl_");//去掉前缀,如:数据库表名为tbl_book,那么生成的dao就为BookDao,否则为Tbl_bookDaostrategyConfig.setRestControllerStyle(true);//设置是否启用RESTful风格strategyConfig.setEntityLombokModel(true);//设置是否启用LombokstrategyConfig.setLogicDeleteFieldName("deleted");//设置逻辑删除字段名strategyConfig.setVersionFieldName("version");//设置乐观锁字段autoGenerator.setStrategy(strategyConfig);//6. 执行生成操作autoGenerator.execute();}
}
  • dao层生成的类还需要添加上 @Mapper 注解

步骤3:测试生成的类

在这里插入图片描述

注意:在使用代码生成器时,application.yml中的内容可以为空
但是如果要在测试中使用方法,需要在application.yml中补齐dataSource的配置

代码生成器生成的结果如上,在Test类中测试

@SpringBootTest
class MybatisplusApplicationTests {@Autowiredprivate IUserService userService;@Testvoid contextLoads(){User user = userService.getById(2L);System.out.println(user);}
}

相关文章:

七、Java框架之MyBatisPlus

黑马课程 文章目录1. MyBatisPlus入门1.1 MyBatisPlus入门案例步骤1&#xff1a;创建spring boot工程步骤2&#xff1a;配置application.yml步骤3&#xff1a;创建数据库表&#xff08;重点&#xff09;步骤4&#xff1a;编写dao层步骤5&#xff1a;测试1.2 标准数据层开发标准…...

C语言柔性数组

目录什么是柔性数组柔性数组的使用什么是柔性数组 柔性数组是在C99中定义的 结构体的最后一个元素允许是未知大小的数组&#xff0c;这就叫柔性书组 柔性数组的长度可以写成0&#xff0c;也可以不规定数组长度 下面两种写法都是正确的 struct S { int i; int a[0];//柔性数…...

支付功能测试用例

Author&#xff1a;ChatGPT用例设计下面是一些支付功能测试用例&#xff1a;账户余额检查&#xff1a;测试用户的账户余额是否准确。支付方式选择&#xff1a;测试用户可以使用的支付方式&#xff0c;包括信用卡、借记卡、电子钱包等。支付金额确认&#xff1a;测试用户输入的支…...

牛客网Python篇数据分析习题(一)

1.现有一个Nowcoder.csv文件&#xff0c;它记录了牛客网的部分用户数据&#xff0c;包含如下字段&#xff08;字段与字段之间以逗号间隔&#xff09;&#xff1a; Nowcoder_ID&#xff1a;用户ID Level&#xff1a;等级 Achievement_value&#xff1a;成就值 Num_of_exercise&a…...

【C语言】“指针类型”与“野指针”

文章目录一、指针是什么❔二、指针和指针类型1.指针-整数2.指针解引用三.野指针1.引起野指针的原因2.如果避免野指针完结一、指针是什么❔ 指针也就是 内存地址 &#xff0c;在计算机上我们访问数据需要通过内存地址来访问&#xff0c;在C语言中&#xff0c;指针变量是用来存放…...

Linux:软链接和硬链接的理解

Linux通过命令行创建快捷方式使用的命令是ln&#xff0c;这里就涉及到了软链接和硬链接&#xff0c;确实有些不好理解&#xff0c;如果你也一样&#xff0c;那么可以继续看下去了 目录ln命令语法实操创建软链接&#xff1a;ln -s [源文件或目录][目标文件或目录]创建硬链接&…...

力扣HOT100 (1-5)

目录 1.两数之和 2.两数相加 拓展到牛客的TOP101的BM11( 链表相加&#xff08;二&#xff09;) 3.无重复的最长子串&#xff08;牛客BM92&#xff09; 解法1&#xff1a; 解法2&#xff1a; 4.寻找两个正序数组的中位数 5.最长回文子串 1.两数之和 思路&#xff1a;用Has…...

车载基础软件——AUTOSAR CP典型应用案例SOME/IP和TSN时间同步

我是穿拖鞋的汉子,魔都中坚持长期主义的一个屌丝工程师! 今天是2023年2月7日,上海还在下着雨,估计是到了梅雨时节(提前到来?),真想说句我劝天公重安排,不让梅雨早时来!!! 老规矩分享一段喜欢的文字,避免自己成为高知识低文化的工科男: “ 我们只需做的,是走好…...

【Linux】操作系统与进程的概念

目录 冯诺依曼体系 注意 为什么CPU不直接访问输入或输出设备&#xff1f; 跨主机间数据的传递 操作系统 管理 进程 描述进程 进程的查看和终止 bash 通过系统调用创建子进程 fork的辨析 冯诺依曼体系 &#x1f956;冯诺依曼结构也称普林斯顿结构&#xff0c;是一种将…...

(1分钟突击面试) 高斯牛顿、LM、Dogleg后端优化算法

高斯牛顿法 LM法 DogLeg方法编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;知识点&#xff1a;高斯牛顿是线搜索方法 LM方法是信赖域方法。编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;这个就是JTJ是…...

d3.js与echarts对比

D3.js 和 ECharts 是两种常用的数据可视化工具&#xff0c;它们有着不同的优缺点&#xff1a; D3.js&#xff1a; 优点&#xff1a; 功能强大&#xff0c;提供了极高的灵活性和定制性&#xff0c;支持多种图表类型&#xff0c;如柱状图、饼图、散点图、树图、网络图等。 可以…...

机器学习之K-means原理详解、公式推导、简单实例(python实现,sklearn调包)

目录1. 聚类原理1.1. 无监督与聚类1.2. K均值算法2. 公式推导2.1. 距离2.2. 最小平方误差3. 实例3.1. python实现3.2. sklearn实现4. 运行&#xff08;可直接食用&#xff09;1. 聚类原理 1.1. 无监督与聚类 在这部分我今天主要介绍K均值聚类算法&#xff0c;在这之前我想提一…...

OBS 进阶 一个从自定义对话框中 传参到插件的例子

目录 一、自定义对话框,传参综合例子 1、自定义对话框 1)自定义对话框类...

在Linux和Windows上编译datax-web-ui源码

记录&#xff1a;375场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;使用apache-maven-3.8.7安装编译datax-web-ui源码。在Windows上操作系统上&#xff0c;使用apache-maven-3.8.7编译datax-web-ui源码。版本&#xff1a;JDK 1.8 node-v14.17.3 npm-6.14.13datax-web-ui开…...

React组件生命周期管理

组件生命,就是组件在不同阶段提供对应的钩子函数,来处理逻辑操作。比如初始化阶段,我们需要初始化组件相关的状态和变量。组件销毁阶段时,我们需要把一些数据结构销毁来节约内存。 React组件生命周期 React组件生命周期分为三个阶段:挂载阶段【Mount】、更新阶段【Updat…...

Linux:全志H3图像codec使用笔记

1. 前言 限于作者能力水平&#xff0c;本文可能存在谬误&#xff0c;因此而给读者带来的损失&#xff0c;作者不做任何承诺。 2. 图像 codec 概述 图像编解码器(codec) 包含 Encoder 和 Decoder 两部分功能。我们用下列分别说明 Encoder 和 Decoder 的工作方式。 ----------…...

【Python小游戏】通过这款专为程序员设计的《极限车神》小游戏,你的打字速度可以赢过专业录入员,这个秘密98%的人都不知道哦~(爆赞)

导语 哈喽&#xff0c;我是你们的木木子&#x1f478;&#xff01; 今天小编要为大家介绍一款小编自己用代码码出来的赛车风格的打字小游戏 取名暂定为《&#x1f697;极限车神&#x1f697;》打字小游戏。 这款Pygame小游戏在玩法上可以说十分创新&#xff0c;不仅能游戏还…...

Springboot扩展点之BeanPostProcessor

前言 Springboot&#xff08;Spring&#xff09;的扩展点其实有很多&#xff0c;但是都有一个共同点&#xff0c;都是围绕着Bean和BeanFactory&#xff08;容器&#xff09;展开的&#xff0c;其实这也很好理解&#xff0c;Spring的核心是控制反转、依赖注入、面向切面编程&…...

Fluent Python 笔记 第 3 章 字典和集合

3.1 泛映射类型 只有可散列 的数据类型才能用作这些映射里的键 字典构造方法&#xff1a; >>> a dict(one1, two2, three3) >>> b {one: 1, two: 2, three: 3} >>> c dict(zip([one, two, three], [1, 2, 3])) >>> d dict([(two, 2…...

大型物流运输管理系统源码 TMS源码

大型物流运输管理系统源码 TMS是一套适用于物流公司的物流运输管理系统&#xff0c;涵盖物流公司内部从订单->提货->运单->配车->点到->预约->签收->回单->代收货款的全链条管理系统。 菜单功能 一、运营管理 1、订单管理&#xff1a;用于客户意向订…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

探索Selenium:自动化测试的神奇钥匙

目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...