mybatis-plus
mybatis-plus入门案例
- 我们基于springboot使用MP
- 1.手动添加MP的起步依赖
- 2.添加dluid的依赖
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.20</version>
</dependency>
数据层代码
- domain(注意id是long类型)
package com.itheima.domain;
public class Book {
private Long id;
private String name;
private String type;
private String description;
public Book() {
}
public Book(Long id, String name, String type, String description) {
this.id = id;
this.name = name;
this.type = type;
this.description = description;
}
/**
* 获取
* @return id
*/
public Long getId() {
return id;
}
/**
* 设置
* @param id
*/
public void setId(Long id) {
this.id = id;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return type
*/
public String getType() {
return type;
}
/**
* 设置
* @param type
*/
public void setType(String type) {
this.type = type;
}
/**
* 获取
* @return description
*/
public String getDescription() {
return description;
}
/**
* 设置
* @param description
*/
public void setDescription(String description) {
this.description = description;
}
public String toString() {
return "Book{id = " + id + ", name = " + name + ", type = " + type + ", description = " + description + "}";
}
}
- dao接口(只需要继承
BaseMapper
类,其余什么都不需要写,甚至连方法名都不需要写。啊啊啊啊,太强了)
package com.itheima.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.domain.Book;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BookDao extends BaseMapper<Book> {
}
- 测试
package com.itheima;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
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 QuickstartApplicationTests {
@Autowired
private BookDao bookDao;
@Test
void testSelectAll() {
final List<Book> books = bookDao.selectList(null);//查询所有
for (Book book : books) {
System.out.println(book);
}
}
}
mybatis-plus简介
标准crud制作
- insert操作
- update操作
提供哪些字段才会修改哪些字段,不提供将不会去修改
之前我们写的update的sql语句一般是set后面默认所有的字段都修改,如果对象中不传入值的话,将都会修改成null - crud完整测试代码
package com.itheima;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
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 QuickstartApplicationTests {
@Autowired
private BookDao bookDao;
@Test
//添加
void testInsert(){
Book book = new Book();
//id不指定,由他自动增长
book.setName("王者荣耀");
book.setType("游戏");
book.setDescription("有趣的游戏");
bookDao.insert(book);
}
//查询全部
@Test
void testSelectAll() {
final List<Book> books = bookDao.selectList(null);//查询所有
for (Book book : books) {
System.out.println(book);
}
}
//按id进行查询
@Test
void testSelectById(){
final Book book = bookDao.selectById(11L);
System.out.println(book);
}
//删除
@Test
void testDelete(){
bookDao.deleteById(1746355658329825281L);
}
//修改
@Test
void testUpdate(){
Book book = new Book();
book.setId(4L);
book.setName("王者荣耀");
//其他没有传入值的属性,将不会修改
bookDao.updateById(book);
}
}
domain开发的简化
-
1.导入lombok的jar包
-
2.使用注解
package com.itheima.domain;
import lombok.*;
@Getter
@Setter
@ToString
@AllArgsConstructor//全参构造
@NoArgsConstructor//无参构造
@EqualsAndHashCode//equals和hanshCode方法覆盖
public class Book {
private Long id;
private String name;
private String type;
private String description;
}
- 简单化
标准分页功能的制作
但是在mybatis-plus中不是叫AOP,而是叫拦截器,拦截查询所有操作并增强他
我们必须保证我们配置的拦截器可以被springboot扫描到,我们可以有下面2种方式
- 1,@import
- 配置类
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
//1.定义MP拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2.添加具体的拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
- 2.将配置类用注解定义成配置类,由boot自动扫描
具体代码 - 分页拦截器
package com.itheima;
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 MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
//1.定义MP拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2.添加具体的拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
@Test
//分页查询
void testSelectPage(){
IPage page = new Page(1,2);
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具体是使用什么sql语句实现分页的呢?
对于分页:1.设置一个拦截器 2.参数设置在IPage中 3.查询结果还是在IPage中
条件查询的三种格式
- 方式一
@Test
//条件查询
void testSelect(){
//方式1:按条件查询
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.lt("id",5);//查询id小于5
final List list = bookDao.selectList(queryWrapper);
System.out.println(list);
}
但是这种方式的列名容易写错
//方式2:lambda格式按条件查询
QueryWrapper<Book> queryWrapper = new QueryWrapper();
queryWrapper.lambda().lt(Book::getId,5);//查询id小于5
final List list = bookDao.selectList(queryWrapper);
System.out.println(list);
- 方式3:对方式2的改进
//方式3:lambda格式按条件查询
LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper();
queryWrapper.lt(Book::getId,5);//查询id小于5
final List list = bookDao.selectList(queryWrapper);
System.out.println(list);
使用的话,推荐使用方式3
- 多条件
前面我们写的条件都是and关系的,那如果我们是or关系的该怎样写呢
条件查询null判定
- 问题描述
- 查询条件的封装
package com.itheima.domain.query;
import lombok.Data;
//封装book表的查询条件
@Data
public class BookQuery {
/*写出可能出现上限和下限的属性(具备查询条件的属性)*/
private Long id;//id的上线
private Long id2;//id的下线
}
解决方案
- 优化方案(调用另外一个条件方法,将判断也封装到里面了)
void testSelect(){
BookQuery bookQuery = new BookQuery();
bookQuery.setId(5L);
/// bookQuery.setId2(2L);
//方式3:lambda格式按条件查询
LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper();
queryWrapper.lt(null!=bookQuery.getId(),Book::getId,bookQuery.getId());//当条件不为空,添加小于条件
queryWrapper.gt(null!=bookQuery.getId2(),Book::getId,bookQuery.getId2());//当添加不为空,添加大于条件
final List list = bookDao.selectList(queryWrapper);
System.out.println(list);
}
查询投影
就是研究查询出来的结果有多少字段
- lambda格式设置
//1.lambda格式设置投影字段
LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper();
queryWrapper.select(Book::getId,Book::getName); //设置投影字段
final List list = bookDao.selectList(queryWrapper);
System.out.println(list);
}
- 2.非lambda格式设置
查询表数据的行数
分组统计
查询条件设置
- 条件设置--等于=
//条件查询
void testSelect(){
//1.lambda格式设置投影字段
LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(Book::getId,5).eq(Book::getType,"计算机理论");//满足id=5并且type=计算机理论
Book book = bookDao.selectOne(queryWrapper);//仅仅查询出一行,使用selectOne
System.out.println(book);
}
- 范围查询
映射匹配兼容性
如果我们重新将实体类的属性名修改一下,这显然工程量巨大
- MP的解决方案
1.MP会直接将我们实体类的类名改成小写后当成表名使用 - 总体演示
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@Data
@TableName("tbl_book")//映射表名
public class Book {
private Long id;
private String name;
@TableField(value = "tp",select = false)//设置该字段不参与查询
private String type;
private String description;
//添加一个表中没有的字段
@TableField(exist = false)//标明该字段表中不存在
private Integer online;
}
DML编程控制
id 生成策略
当id生成策略为input(即需要自动手动指定id),则我们需要在数据库中不设定id自增,而是手动传入id
我们的mp默认使用雪花算法
如果我们要使用一种id自增策略,我们需要在每个实体类的id字段上都添加上测试,这太麻烦了
- 在配置文件中配置全局id自增策略(添加操作)
- 在配置文件中配置类名和表名的全局映射
多数据操作(删除与查询)
- mp中实现多条数据同时删除
void testDelete(){
List<Long>list = new ArrayList<>();
list.add(1746479432933031937L);
list.add(1746479492160700417L);
list.add(1746482543491780609L);
list.add(1746484259935191041L);
bookDao.deleteBatchIds(list);//根据id进行批量删除
}
- 实现多条数据同时查询(和前面的差不多)
逻辑删除(企业开发中经常用到)
- 1.给我们的表添加上逻辑删除字段
- 2.在类中设置逻辑删除字段
- 3.进行删除操作
标明逻辑删除后,对查询操作的影响
总结:当添加逻辑删除字段后,所以的查询操作将自动添加where deleted=0的条件
配置全局逻辑删除字段
重要提示:配置全局逻辑删除字段对每个表都自动配置逻辑删除字段,但是如果表中没有添加对应的逻辑删除字段,则该配置对他没有用,也不会报错
乐观锁
本质上就是二值信号量,就是是互斥锁来实现同步。version也就是信号量
具体实现看笔记
使用乐观锁拦截器动态修改version的值
快速开发--代码生成器
- 添加依赖
代码生成器支持自己配置模板,这里不去做了解
- 生成器类的配置
public class CodeGenerator {
public static void main(String[] args) {
//1.获取代码生成器的对象
AutoGenerator autoGenerator = new AutoGenerator();
//设置数据库相关配置
DataSourceConfig dataSource = new DataSourceConfig();
dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
对于代码生成器中的代码内容,我们可以直接从官方文档中获取代码进行修改,
https://mp.baomidou.com/guide/generator.html
步骤5:运行程序
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?
serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("root");
autoGenerator.setDataSource(dataSource);
//设置全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/mybatisplus_04_ge
nerator/src/main/java"); //设置代码生成位置
globalConfig.setOpen(false); //设置生成完毕后是否打开生成代码所在的目录
globalConfig.setAuthor("黑马程序员"); //设置作者
globalConfig.setFileOverride(true); //设置是否覆盖原始生成的文件
globalConfig.setMapperName("%sDao"); //设置数据层接口名,%s为占位符,指
代模块名称
globalConfig.setIdType(IdType.ASSIGN_ID); //设置Id生成策略
autoGenerator.setGlobalConfig(globalConfig);
//设置包名相关配置
PackageConfig packageInfo = new PackageConfig();
packageInfo.setParent("com.aaa"); //设置生成的包名,与代码所在位置不冲突,
二者叠加组成完整路径
packageInfo.setEntity("domain"); //设置实体类包名
packageInfo.setMapper("dao"); //设置数据层包名
autoGenerator.setPackageInfo(packageInfo);
//策略设置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("tbl_user"); //设置当前参与生成的表名,参数为可
变参数
strategyConfig.setTablePrefix("tbl_"); //设置数据库表的前缀名称,模块名 =
数据库表名 - 前缀名 例如: User = tbl_user - tbl_
strategyConfig.setRestControllerStyle(true); //设置是否启用Rest风格
strategyConfig.setVersionFieldName("version"); //设置乐观锁字段名
strategyConfig.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段名
strategyConfig.setEntityLombokModel(true); //设置是否启用lombok
autoGenerator.setStrategy(strategyConfig);
//2.执行生成操作
autoGenerator.execute();
}
}
生成代码我们需要的是:1.导入依赖 2.编写代码生成了类(不需要另外进行配置)