目录
5.1添加分页插件(在com.egcxy.config下面)
一、Mybatis-Plus简介
1.Mybatis-Plus概念
官网:MyBatis-Plus (baomidou.com)https://baomidou.com/
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
MyBatis-Plus提供了通用的mapper和service,可以在不编写任何SQL语句的情况下,快速的实现对单表的CRUD.批量、逻辑删除、分页等操作。
2.Mybatis-Plus的特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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.支持的数据库
MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb,informix,TDengine,redshift
(下面演示的代码示例,涉及到的数据库采用的MySQL)
二、代码生成器
1.搭建一个SpringBoot框架
①创建一个新的项目
这里的依赖你可以选择加也可以不加,点击创建即可(我这里没有加)
②添加需要用到的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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.5.1</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>
<!-- 阿里数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.2</version>
</dependency>
<!-- mybatis-plus代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
2.连接数据库(配置application.yml)
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demol2?CharacterEncoding=UTF-8
password: 423423
username: root
3.使用代码生成器
在com.ecgxy.config包下创建一个CodeGenerato生成类
package com.egcxy.config;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.ArrayList;
import java.util.List;
public class CodeGenerator {
public static void main(String[] args) {
//数据库连接
String url = "jdbc:mysql://localhost:3306/demol2?CharacterEncoding=UTF-8";//数据库url
String username = "root";//账号
String password = "423423";//密码
String module = "";//项目模块名,如果是有父项目的话,需要配置。
//全局配置参数
String author = "huangwei";//作者
String outputDir = System.getProperty("user.dir")+ "/" + module +"/src/main/java";//指定输出目录
//包配置参数
String parent = "com.egcxy";//父包名
String moduleName = "";//父包模块名
String entity = "entity";//Entity 实体类包名
String mapper = "mapper";//Mapper 包名
String mapperXml = "mapper.xml";//Mapper XML 包名
String service = "service";//Service 包名
String serviceImpl = "service.Impl";//Service Impl 包名
String controller = "controller";//Controller 包名*/
//要生成的数据库表
List<String> tables = new ArrayList<>();
tables.add("account");
tables.add("dep");
tables.add("phone");
tables.add("stu");
tables.add("user");
tables.add("brand");
//开始生成
FastAutoGenerator.create(url,username,password)
//全局配置
.globalConfig(builder -> {
builder.author(author)
.outputDir(outputDir)
.disableOpenDir() //生成之后不打开目录
/*.enableSwagger()//开启swagger*/
.fileOverride() // 覆盖已生成文件
.dateType(DateType.ONLY_DATE) //定义生成的实体类中日期类型 DateType.ONLY_DATE 默认值: DateType.TIME_PACK
.commentDate("yyyy-MM-dd");//注释日期
})
//包配置
.packageConfig(builder -> {
builder.parent(parent)
.moduleName(moduleName)
.entity(entity)
.mapper(mapper)
.xml(mapperXml)
.service(service)
.serviceImpl(serviceImpl)
.controller(controller);
})
//策略配置
.strategyConfig(builder -> {
builder.addInclude(tables)
// .addTablePrefix("sys_") // 设置过滤表前缀
//开启生成实体类
.entityBuilder()
.enableLombok()//开启 lombok 模型
.enableTableFieldAnnotation()//开启生成实体时生成字段注解
//开启生成mapper
.mapperBuilder()
//.enableBaseResultMap()//启用 BaseResultMap 生成
.superClass(BaseMapper.class)//设置父类
.enableMapperAnnotation()//开启 @Mapper 注解
.formatMapperFileName("%sMapper")//格式化 mapper 文件名称
.formatXmlFileName("%sMapper")//格式化 xml 实现类文件名称
//开启生成service及impl
.serviceBuilder()
.formatServiceFileName("%sService")//格式化 service 接口文件名称
.formatServiceImplFileName("%sServiceImpl")//格式化 service 实现类文件名称
//开启生成controller
.controllerBuilder()
// 映射路径使用连字符格式,而不是驼峰
//.enableHyphenStyle()
.formatFileName("%sController")//格式化文件名称
.enableRestStyle();
})
.templateEngine(new VelocityTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
//.templateConfig(builder -> builder.controller(""))//关闭生成controller
.execute();
}
}
生成的代码结构如下:
三、Mybatis-Plus主要的注解
1.@TableName
- 描述:表名注解,标识实体类对应的表
- 使用位置:实体类
- 使用案例:
package com.egcxy.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
@TableName("user")
public class User1 {
private Long id;
private String name;
private Integer age;
private Integer gender;
}
- 相关属性:
属性 | 类型 | 必须指定 | 默认值 | 描述 |
value | String | 否 | "" | 表名 |
schema | String | 否 | "" | schema |
keepGlobalPrefix | boolean | 否 | false | 是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时) |
resultMap | String | 否 | "" | xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定) |
autoResultMap | boolean | 否 | false | 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入) |
excludeProperty | String[] | 否 | {} | 需要排除的属性名 |
2.@TableId
- 描述:主键注解
- 使用位置:实体类主键字段
- 使用案例:
package com.egcxy.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
@TableName("user")
public class User1 {
//这个注解是用来申明主键,里面的type是用来声明这是一个什么样的主键
@TableId(type = IdType.AUTO)//自增的主键id
private Long id;
private String name;
private Integer age;
private Integer gender;
}
- 相关属性:
属性 类型 必须指定 默认值 描述 value String 否 "" 主键字段名 type Enum 否 IdType.NONE 指定主键类 -
IdType常使用的值:
值 | 描述 |
---|---|
AUTO | 数据库 ID 自增 |
NONE | 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | insert 前自行 set 主键值 |
ASSIGN_ID | 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默认实现类为DefaultIdentifierGenerator 雪花算法) |
ASSIGN_UUID | 分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator 的方法nextUUID (默认 default 方法) |
3.@TableField
- 描述:字段注解(非主键)
- 使用案例:
package com.egcxy.entity;
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.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
@TableName("user")
public class User1 {
//这个注解是用来申明主键,里面的type是用来声明这是一个什么样的主键
@TableId(type = IdType.AUTO)//自增的主键id
private Long id;
@TableField("nickname")
private String name;
private Integer age;
private Integer gender;
}
- 主要相关属性
属性 类型 必须指定 默认值 描述 value String 否 "" 数据库字段名 exist boolean 否 true 是否为数据库表字段 condition String 否 "" 字段 where
实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的%s=#{%s}
,参考(opens new window)update String 否 "" 字段 update set
部分注入,例如:当在version字段上注解update="%s+1"
表示更新时会set version=version+1
(该属性优先级高于el
属性)nsertStrategy Enum 否 FieldStrategy.DEFAULT 举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategy Enum 否 FieldStrategy.DEFAULT 举例:IGNORED update table_a set column=#{columnProperty}
whereStrategy Enum 否 FieldStrategy.DEFAULT 举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fill Enum 否 FieldFill.DEFAULT 字段自动填充策略 select boolean 否 true 是否进行 select 查询
4.@Version
- 描述:乐观锁注解、标记
@Version
在字段上
5.@EnumValue
- 描述:普通枚举类注解(注解在枚举字段上)
6.@TableLogic
- 描述:表字段逻辑处理注解(逻辑删除)
- 相关属性
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 逻辑未删除值 |
delval | String | 否 | "" | 逻辑删除值 |
7.@KeySequence
- 描述:序列主键策略
oracle
- 属性:value、dbType
- 相关属性:
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 序列名 |
dbType | Enum | 否 | DbType.OTHER | 数据库类型,未配置默认使用注入 IKeyGenerator 实现,多个实现必须指定 |
四、条件构造器
Wrapper:条件构造器,最顶端的一个类
AbstractWrapper:用于sql语句条件的封装,主要是封装where条件
QueryWrapper:查询条件封装,继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取
UpdateWrapper:更新条件封装,继承自 AbstractWrapper
,自身的内部属性 entity
也用于生成 where 条件及 LambdaUpdateWrapper
, 可以通过 new UpdateWrapper().lambda()
方法获取!
AbstractLambdaWrapper:具有Lambda语法的条件封装
LambdaQueryWrapper:具有Lambda语法查询条件封装
LambdaUpdateWrapper:具有Lambda语法更新条件封装
常用条件连接
1.eq(等于=)
eq(R column, Object val)
eq(boolean condition, R column, Object val)
使用例如:eq("name"."xiaoming")=======>name='xiaoming'
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("name","xiaoming1");
2.ne(不等于<>)
ne(R column, Object val)
ne(boolean condition, R column, Object val)
例如:ne("name"."xiaoming")=======>name<>'xiaoming'
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.ne("name","xiaoming1");
3.get(大于>)
gt(R column, Object val)
gt(boolean condition, R column, Object val)
例如:gt("age"."18") =======> ge>18
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.gt("age",18);
4.lt(小于<)
lt(R column, Object val)
lt(boolean condition, R column, Object val)
例如:lt("age"."18") =======> ge<18
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.lt("age",18);
5.between
between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
例如:between("age",18,30) ====> age between 18 and 30
QueryWrapper<Tests> testsQueryWrapper = new QueryWrapper<>();
testsQueryWrapper.between("age",18,35);
6.like(like '%值%')
like(R column, Object val)
like(boolean condition, R column, Object val)
例如:like("name","美") ====> name like '%美%'
7.notLike(not like '%值%')
notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
例如:notLike("name","美") ====> name not like '%美%'
8.in
in(R column, Collection<?> value)
in(boolean condition, R column, Collection<?> value)
- 字段 IN (value.get(0), value.get(1), ...)
- 例如:in("age",{1,2,3}) ====> age in (1,2,3)
in(R column, Object... values)
in(boolean condition, R column, Object... values)
- 字段 IN (v0, v1, ...)
- 例如:in("age",10,20,30) ===> age in (10,20,30)
9.groupBy(分组)
groupBy(R... columns)
groupBy(boolean condition, R... columns)
- 分组:GROUP BY 字段, ...
- 例如: groupBy("id","name") ====> group by id,name
五、执行SQL分析打印
1.在pom.xml文件中将p6spy依赖引入
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>
2.application.yml配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
#driver-class-name: com.mysql.cj.jdbc.Driver
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/demol2?CharacterEncoding=UTF-8
# url: jdbc:mysql://localhost:3306/demol2?CharacterEncoding=UTF-8
password: 423423
username: root
main:
banner-mode: off #关闭springboot启动图标
mybatis-plus:
config-location:
log-impl: org.apache.ibatis.logging.stdout.Std0utImpl #打印SQL到控制台
global-config:
banner: off #关闭mybatisplus启动图标
3.spy.properties配置
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
六、CRUD 接口
这里主要讲解经常使用到的接口
1.Service CRUD 接口及相关方法
- 通用 Service CRUD 封装IService (opens new window)接口,进一步封装 CRUD 采用 get
查询单行
、remove删除
、list查询集合、
page分页
前缀命名方式区分Mapper
层避免混淆, - 泛型
T
为任意实体对象 - 建议如果存在自定义通用 Service 方法的可能,请创建自己的
IBaseService
继承Mybatis-Plus
提供的基类 - 对象
Wrapper
为 条件构造器
1.1Save(插入)
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
Collection<T> | entityList | 实体对象集合 |
int | batchSize | 插入批次数量 |
1.2SaveOrUpdate(修改插入)
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
Wrapper<T> | updateWrapper | 实体对象封装操作类 UpdateWrapper |
Collection<T> | entityList | 实体对象集合 |
int | batchSize | 插入批次数量 |
1.3Remove(删除)
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | queryWrapper | 实体包装类 QueryWrapper |
Serializable | id | 主键 ID |
Map<String, Object> | columnMap | 表字段 map 对象 |
Collection<? extends Serializable> | idList | 主键 ID 列表 |
1.4Update(更新)
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | updateWrapper | 实体对象封装操作类 UpdateWrapper |
T | entity | 实体对象 |
Collection<T> | entityList | 实体对象集合 |
int | batchSize | 更新批次数量 |
1.5Get
// 根据 id 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Serializable | id | 主键 ID |
Wrapper<T> | queryWrapper | 实体对象封装操作类 QueryWrapper |
boolean | throwEx | 有多个 result 是否抛出异常 |
T | entity | 实体对象 |
Function<? super Object, V> | mapper | 转换函数 |
1.6List
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | queryWrapper | 实体对象封装操作类 QueryWrapper |
Collection<? extends Serializable> | idList | 主键 ID 列表 |
Map<String, Object> | columnMap | 表字段 map 对象 |
Function<? super Object, V> | mapper | 转换函数 |
1.7Page
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
IPage<T> | page | 翻页对象 |
Wrapper<T> | queryWrapper | 实体对象封装操作类 QueryWrapper |
1.8Count
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | queryWrapper | 实体对象封装操作类 QueryWrapper |
2.Mapper CRUD 接口
- 通用 CRUD 封装BaseMapper (opens new window)接口,为
Mybatis-Plus
启动时自动解析实体表关系映射转换为Mybatis
内部对象注入容器 - 泛型
T
为任意实体对象 - 参数
Serializable
为任意类型主键Mybatis-Plus
不推荐使用复合主键约定每一张表都有自己的唯一id
主键 - 对象
Wrapper
为 条件构造器
2.1Inser(插入)
// 插入一条记录
int insert(T entity);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
2.2Delete
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | wrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Serializable | id | 主键 ID |
Map<String, Object> | columnMap | 表字段 map 对象 |
2.3Update
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 (set 条件值,可为 null) |
Wrapper<T> | updateWrapper | 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) |
2.4Select
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper)
参数说明:
类型 | 参数名 | 描述 |
---|---|---|
Serializable | id | 主键 ID |
Wrapper<T> | queryWrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Map<String, Object> | columnMap | 表字段 map 对象 |
IPage<T> | page | 分页查询条件(可以为 RowBounds.DEFAULT) |
七、Mybatis-Plus——实现增删改查
1.插入数据
@SpringBootTest
class Mybatispuls001ApplicationTests {
@Autowired
User1Service user1Service;
@Autowired
User1Mapper user1Mapper;
// @Autowired
// UsersMapper usersMapper;
@Test
void contextLoads() {
//插入数据
User1 user = new User1();
user.setAge(10);
user.setName("花花");
user.setGender(1);
// mapper层插入
user1Mapper.insert(user);
Long id = user.getId();
System.out.println("id" + id);
//这里是service中封装的插入方法
// boolean isSuccess = user1Service.save(user);
// Long id = user.getId();
// System.out.println("返回结果" + isSuccess + "id" + id);
//伪批量插入
List<User1> user1List = new ArrayList<>();
for (int i = 10; i < 20; i++) {
User1 user1 = new User1();
user1.setAge(10 + i);
user1.setGender(1 + i);
user1.setName("xiaoming" + i);
user1List.add(user1);
}
boolean isSuccess = user1Service.saveBatch(user1List);
System.out.println("返回结果" + isSuccess);
//批量保存或者更新
List<User1> user1List1 = new ArrayList<>();
for (int i = 3; i < 10; i++) {
User1 user1 = new User1();
user1.setAge(10 + i);
user1.setGender(1 + i);
user1.setName("xiaoming" + i);
user1List.add(user1);
}
boolean isSuccess1 = user1Service.saveOrUpdateBatch(user1List1);
System.out.println("返回结果" + isSuccess);
// user1Service.saveOrUpdateBatch();//可以指定批量的大小
}
}
2.删除数据
@Test
void deleteTest() {
//Mapper层删除功能
//1.1根据主键id删除数据(直接传id)
int count = user1Mapper.deleteById(9L);
System.out.println("删除了:" + count + "条数据");
//1.2根据主键id删除数据(传实体类)
User1 user = new User1();
user.setId(8L);
int count1 = user1Mapper.deleteById(user);
System.out.println("删除了:" + count1 + "条数据");
//1.3根据主键id批量删除数据
List<Long> ids = new ArrayList<>();
ids.add(1L);
ids.add(2L);
//delete from t_user where id in ids
user1Mapper.deleteBatchIds(ids);
//通过构造器
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.ne("name","xiaoming1");
wrapper.gt("age",11);
//delete from t_user where (name="xiaoming1" and age=11)
user1Mapper.delete(wrapper);
//使用lambda表达式删除数据
user1Mapper.delete(new QueryWrapper<User1>()
.lambda()
.eq(User1::getName,"xiaoming1")
.eq(User1::getAge,11)
);
//使用map设置条件删除
Map<String,Object> col = new HashMap<>();
col.put("name","xiaoming2");
col.put("age",12);
int count2 = user1Mapper.deleteByMap(col);
System.out.println("删除了:" + count2 + "条数据");
}
3.更新数据
@Test
void updateTest() {
//更新数据
//Mapper层更新
User1 user = User1.builder()
.name("小小")
.id(5L)
.gender(0)
.build();
int count = user1Mapper.updateById(user);
System.out.println("更新了:" + count + "条数据");
//通过wrapper进行跟新
User1 user1 = User1.builder()
.name("花花")
.gender(0)
.build();
UpdateWrapper<User1> wrapper = new UpdateWrapper<>();
wrapper.eq("age",13);
int count1 = user1Mapper.update(user1,wrapper);
System.out.println("更新了:" + count1 + "条数据");
//service层更新数据
UpdateWrapper<User1> user1UpdateWrapper = new UpdateWrapper<>();
user1UpdateWrapper.set("name","xixi");
user1UpdateWrapper.eq("id",5L).eq("age",13);
boolean isSuccess = user1Service.update(user1UpdateWrapper);
System.out.println(isSuccess);
}
4.查询数据
@Test
void selectTest() {
//查询数据
//Mapper层查询
//根据主键id查询
User1 user = user1Mapper.selectById(5L);
System.out.println(user.toString());
//通过构造wrapper条件查询一条数据
QueryWrapper<User1> queryWrapper = new QueryWrapper<>();
//设置查询字段:仅查询name、id字段
queryWrapper.select("id","name");
//添加查询条件
queryWrapper.eq("id",6L);
User1 user1 = user1Mapper.selectOne(queryWrapper);
System.out.println(user1.toString());
//根据主键id进行批量查询
List<User1> user1List = user1Mapper.selectBatchIds(Arrays.asList(5L,6L,7L));
System.out.println(user1List.toString());
//通过wrapper组装查询条件,查询全部数据
QueryWrapper<User1> queryWrapper1 = new QueryWrapper<>();
//设置查询字段:仅查询name、id字段
queryWrapper1.select("id","name");
//添加查询条件
queryWrapper1.eq("age",30);
List<User1> users = user1Mapper.selectList(queryWrapper1);
//根据columnMap设置查询挑条件
Map<String,Object> colMap = new HashMap<>();
colMap.put("name","xixi");
colMap.put("age",13);
//select * from t_user where name="xixi" and age=13
List<User1> user1List1 = user1Mapper.selectByMap(colMap);
//根据wrapper条件,查询记录总数
QueryWrapper<User1> queryWrapper2 = new QueryWrapper<>();
queryWrapper2.eq("name","xixi").eq("age",13);
long count = user1Mapper.selectCount(queryWrapper2);//获取总量
System.out.println(count);
//service层查询数据
User1 user2 = user1Service.getById(5L);//根据id获取数据
//通过wrapper查询一条数据,当结果出现多条数据的时候是会抛出异常
QueryWrapper<User1> queryWrapper3 = new QueryWrapper<>();
queryWrapper3.eq("name","xixi").eq("id",5L);
//执行的sql语句:select * from t_user where id=5 and name = "xixi"
User1 user3 = user1Service.getOne(queryWrapper3);
//通过list开头的方法来查询多条数据
//条件查询
QueryWrapper<User1> queryWrapper4 = new QueryWrapper<>();
queryWrapper4.eq("name","xixi").eq("id",5L);
//执行的sql语句:select * from t_user where id=5 and name = "xixi"
List<User1> user1s = user1Service.list(queryWrapper4);
//根据id列表查询数据
//执行的sql语句:select * from t_user where id in(5,6)
List<User1> user1List2 = user1Service.listByIds(Arrays.asList(5L,6L));
//通过map构造查询条件
Map<String,Object> cloMap = new HashMap<>();
cloMap.put("name","xixi");
cloMap.put("age",13);
//执行的sql语句:select * from t_user where age=13 and name = "xixi"
List<User1> user1List3 = user1Service.listByMap(cloMap);
//
// //获取查询总数
QueryWrapper<User1> queryWrapper5 = new QueryWrapper<>();
queryWrapper5.eq("name","xixi").eq("id",5L);
user1Service.count(queryWrapper5);//获取查询总数
}
5.分页查询
5.1添加分页插件(在com.egcxy.config下面)
package com.egcxy.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.egcxy.mapper")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
5.2实现分页
//mapper层的分页查询
QueryWrapper<User1> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("age",30);
Page<User1> page = new Page<>(2,10);//查询第二页,每页10条数据
page = user1Mapper.selectPage(page,queryWrapper);
System.out.println("总共记录数:" + page.getTotal());
System.out.println("总共多少页:" + page.getPages());
System.out.println("当前页码:" + page.getCurrent());
//获取当前数据
List<User1> user1s = page.getRecords();
user1s.forEach(System.out::println);
//service层分页查询
QueryWrapper<User1> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("age",30);
Page<User1> page = new Page<>(2,10);//查询第二页,每页10条数据
page = user1Service.page(page,queryWrapper);
System.out.println("总共记录数:" + page.getTotal());
System.out.println("总共多少页:" + page.getPages());
System.out.println("当前页码:" + page.getCurrent());
//获取当前数据
List<User1> user1s = page.getRecords();
user1s.forEach(System.out::println);
6.多表关联查询和分页查询
6.1建立order实体和orderVo实体
@Data
@Getter
@Setter
@TableName("t_order")
public class Order {
private Long id;
private Long orderId;
private Long userId;//用户id
private String goodsName;//商品名称
private BigDecimal goodsPrice;//商品价格
}
@Data
@Getter
@Setter
public class OrderVo {
private Long orderId;
private Long userId;//用户id
private String goodsName;//商品名称
private BigDecimal goodsPrice;//商品价格
private String userName;
private Integer userAge;
private Integer userGender;
}
6.2建立mapper文件
@Mapper
public interface User1Mapper extends BaseMapper<User1> {
//查询订单列表
List<OrderVo> selectOrders();
//关联分页查询
IPage<OrderVo> selectOrderPage(IPage<OrderVo> page, @Param(Constants.WRAPPER) QueryWrapper<OrderVo> wrapper);// @Param绑定参数
}
6.3mapper配置文件
<?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="com.egcxy.mapper.User1Mapper">
<resultMap id="orderMap" type="com.egcxy.entity.OrderVo">
<result property="userName" column="name"></result>
<result property="userAge" column="age"></result>
<result property="userGender" column="gender"></result>
<result property="orderId" column="order_id"></result>
<result property="userId" column="user_id"></result>
<result property="goodsName" column="goods_name"></result>
<result property="goodsPrice" column="goods_price"></result>
</resultMap>
<!-- <select id="selectOrders" resultMap="orderMap">-->
<!-- select o.order_id,o.user_id,o.goods_name,o.goods_price,u.name,u.age,u.gender-->
<!-- from t_order as o left join t_user as u on o.user_id=u.id;-->
<!-- </select>-->
<!--分页查询,${ew.customSqlSement}这个可以实现分页-->
<select id="selectOrderPage" resultMap="orderMap">
select o.order_id,o.user_id,o.goods_name,o.goods_price,u.name,u.age,u.gender
from t_order as o left join t_user as u on o.user_id=u.id
${ew.customSqlSegment}
</select>
</mapper>
6.4测试代码
//多表关联查询
//需求:假设前端需要展示数据:订单号、商品名称、商品价格、下单用户名、下单用户年龄、性别
//执行的sql语句:select o.order_id,o.user_id,o.goods_name,o.goods_price,u.name,u.age,u.gender from t_order as o left join t_user as u on o.user_id=u.id;
List<OrderVo> orderVos = user1Mapper.selectOrders();
orderVos.forEach(System.out::println);
//关联分页查询
//查询第一页,每页数据显示10条
Page<OrderVo> page = new Page<>(1,10);
//需要手动关闭关闭qal优化(${ew.customSqlSegment}),如果不关闭就只会查询主表
page.setOptimizeCountSql(false);
//组装查询条件:age=30
QueryWrapper<OrderVo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("age",18);
IPage<OrderVo> page1 = user1Mapper.selectOrderPage(page,queryWrapper);
System.out.println("总共记录数:" + page1.getTotal());
System.out.println("总共多少页:" + page1.getPages());
System.out.println("当前页码:" + page1.getCurrent());
//System.out.println("当前查询数据:" + page1.getRecords());
List<OrderVo> orderVos1 = page.getRecords();
orderVos1.forEach(System.out::println);