MyBatisPlus

1.简介

1.什么是Mybatis-plus?

   MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

  官网:https://mp.baomidou.com/

2.开发环境准备

1.配置数据库环境,创建一张测试表

2.创建springboot项目,引入依赖

<!--mybatis plus 起步依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>

3.编写DataSource相关配置

spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456

4.编写实体类

@Data
//指定表名
@TableName("user_info")
public class UserInfo implements Serializable {
//指定表的id
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
//指定表中的字段名
@TableField("name")
private String name;
private Integer sex;
private Integer age;
private String address;
private String mobile;
private String email;
@TableField(exist = false)
private String test;
//逻辑删除,1:删除,0:未删
@TableLogic(value = "0", delval = "1")
private Integer disabled;
}
1) @TableField("name") 指定映射关系。
  • 实体类的属性名和数据库的字段名自动映射。
  • 自动映射条件:名称一样,或者数据库字段使用_分割,实体类属性名使用驼峰名称
  • 否则需要使用@TableField("name") 指定映射关系。
2)@TableField(exist = false) 忽略某个字段的查询和插入。
3) @TableId(type = IdType.AUTO)设置id生成策略:AUTO 数据库自增。
  • AUTO 数据库ID自增,依赖于数据库。在插入操作生成SQL语句时,不会插入主键这一列
  • NONE 未设置主键类型。用户输入,为空则会根据主键的全局策略自动生成
  • INPUT 需要手动设置主键,若不设置。插入操作生成SQL语句时,主键这一列的值会是null
  • ID_WORKER(Long) 当实体类的主键属性为空时,才会自动填充
  • ID_WORKER_STR(String) 当实体类的主键属性为空时,才会自动填充
  • UUID 当实体类的主键属性为空时,才会自动填充,使用UUID
4)@TableLogic(value = "0", delval = "1")设置逻辑删除字段,并设置删除与未删的代表值
添加该注解之后:
  • 删除转变为更新,调用mp提供的删除接口时,更新disable字段0->1
  • 只对自动注入的SQL起效
  • 查询时自动生成where disable=0查询
  • 更新时自动生成where disable=0条件防止更新到已删除数据
  • 自己写的删除接口依然为物理删除
不添加此注解时:
  • mp提供的删除接口默认为物理删除

5.启动类增加 @MapperScan 注解,指定dao包的位置

@SpringBootApplication
@MapperScan("com.jinrui.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}

3.Mapper 接口

编写dao

使用mp定义Mapper,需要让Mapper接口继承 BaseMapper接口。

@Mapper
public interface UserInfoDao extends BaseMapper<UserInfo> {
}

1.增加

// 插入一条记录

int insert(T entity);

类型

参数名

描述

T entity 实体对象

2.删除

// 根据 entity 条件,删除记录
int delete(Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(Map<String, Object> columnMap);

类型参数名描述
Wrapper<T> wrapper 实体对象封装操作类(可以为 null)
Collection<? extends Serializable> idList 主键ID列表(不能为 null 以及 empty)
Serializable id 主键ID
Map<String, Object> columnMap 表字段 map 对象

3.修改

// 根据 whereWrapper 条件,更新记录
int update(Wrapper<T> updateWrapper);
// 根据 ID 修改
int updateById(T entity);

类型参数名描述
T entity 实体对象 (set 条件值,可为 null)
Wrapper<T> updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)

4.查询

// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录,只展示查询的字段,不展示为null的字段
List<Map<String, Object>> selectMaps(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(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)

条件构造器

AbstractWrapper是QueryWrapper和 UpdateWrapper的父类,用于生成 sql 的 where 条件

AbstractWrapper:
like(R column, Object val)
like(boolean condition, R column, Object val)
  • LIKE '%值%'

  • 例: like("name", "王")--->name like '%王%
eq(R column, Object val)
eq(boolean condition, R column, Object val)
  • 等于 =

  • 例: eq("name", "老王")--->name = '老王'

likeLeft(R column, Object val)
likeLeft(boolean condition, R column, Object val)
  • LIKE '%值'

  • 例: likeLeft("name", "王")--->name like '%王'

likeRight(R column, Object val)
likeRight(boolean condition, R column, Object val)
  • LIKE '值%'
  • 例: likeRight("name", "王")--->name like '王%'
gt(R column, Object val)
gt(boolean condition, R column, Object val)
  • 大于 >
  • 例: gt("age", 18)--->age > 18
ge(R column, Object val)
ge(boolean condition, R column, Object val)
  • 大于等于 >=

  • 例: ge("age", 18)--->age >= 18

lt(R column, Object val)
lt(boolean condition, R column, Object val)
  • 小于 <
  • 例: lt("age", 18)--->age < 18
le(R column, Object val)
le(boolean condition, R column, Object val)
  • 小于等于 <=
  • 例: le("age", 18)--->age <= 18
isNull(R column)
isNull(boolean condition, R column)
  • 字段 IS NULL
  • 例: isNull("name")--->name is null
isNotNull(R column)
isNotNull(boolean condition, R column)
  • 字段 IS NOT NULL
  • 例: isNotNull("name")--->name is not null
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)
orderBy(boolean condition, boolean isAsc, R... columns)
  • 排序:ORDER BY 字段, ...
  • 例: orderBy(true, true, "id", "name")--->order by id ASC,name ASC
between(R column, Object val1, Object val2)
between(boolean condition, R column, Object val1, Object val2)
  • BETWEEN 值1 AND 值2
  • 例: between("age", 18, 30)--->age between 18 and 30
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
  • NOT BETWEEN 值1 AND 值2
  • 例: notBetween("age", 18, 30)--->age not between 18 and 30
groupBy(R... columns)
groupBy(boolean condition, R... columns)
  • 分组:GROUP BY 字段, ...
  • 例: groupBy("id", "name")--->group by id,name
having(String sqlHaving, Object... params)
having(boolean condition, String sqlHaving, Object... params)
  • HAVING ( sql语句 )
  • 例: having("sum(age) > 10")--->having sum(age) > 10
  • 例: having("sum(age) > {0}", 11)--->having sum(age) > 11
or()
or(boolean condition)
  • 拼接 OR
  • 主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)
apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
  • 该方法可用于数据库函数 动态入参的params对应前面的{index}部分.这样是不会有sql注入风险的,反之会有!
  • apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")

QueryWrapper:
select(String... sqlSelect)
  • 设置查询字段
  • 例: select("id", "name", "age")->select id,name,age
UpdateWrapper:
set(String column, Object val)
set(boolean condition, String column, Object val)
  • SQL SET 字段
  • 例: set("name", "wang")
  • 例: set("name", "")--->数据库字段值变为空字符串
  • 例: set("name", null)--->数据库字段值变为null
setSql(String sql)
  • 设置 SET 部分 SQL
  • 例: setSql("name = 'wang'")

4.Service接口

说明:

通用 Service CRUD 封装IService 接口,进一步封装 CRUD 采用 get 查询、单行 remove 删除、 list 查询集合、 page 分页, 前缀命名方式区分 Mapper 层避免混淆。

需要继承Service类

public interface UserInfoService extends IService<UserInfo> {}

建议如果存在自定义通用 Service 方法,请创建自己的 BaseService 继承 Mybatis-Plus 提供的基类

public interface UserInfoService extends BaseService<UserInfo> {}
public interface BaseService extends IService<UserInfo> {}

 

接口介绍:

#Save

// 插入一条记录(选择字段,策略插入)

boolean save(T entity);

// 插入(批量)

boolean saveBatch(Collection<T> entityList);

类型

参数名

描述

T entity 实体对象
Collection<T> entityList 实体对象集合

SaveOrUpdate

// 主键id存在更新记录,否则插入一条记录

boolean saveOrUpdate(T entity);

// 批量修改插入

boolean saveOrUpdateBatch(Collection<T> entityList);

// 批量修改插入

boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

类型参数名描述
T entity 实体对象
Collection<T> entityList 实体对象集合
int batchSize 插入批次数量

#Remove

// 根据 entity 条件,删除记录
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列表

#Update

// 根据 updateWrapper条件,更新记录
boolean update(T updateEntity, Wrapper<T> updateWrapper);
// 根据 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 更新批次数量

#Get

// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);

类型参数名描述
Serializable id 主键ID
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper
boolean throwEx 有多个 result 是否抛出异常
T entity 实体对象

#List

// 查询所有
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);
// 查询所有列表,不显示为null的字段
List<Map<String, Object>> listMaps();
// 根据条件查询所有列表,不显示为null的字段
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录,只显示第一个字段
List<Object> listObjs();
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);

类型参数名描述
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper
Collection<? extends Serializable> idList 主键ID列表
Map<?String, Object> columnMap 表字段 map 对象

#Count

// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);

 

类型

参数名

描述

Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper

5.分页插件

写mybatis-plus配置类,用来配置使用的数据库

@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor= new PaginationInterceptor();
paginationInterceptor.setDialectType("mysql");
return paginationInterceptor;
}
}

写service,可以调用mp中service层提供的分页接口和Ipage插件进行分页。

// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询,不显示null字段
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询,不显示null字段
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

类型参数名描述
IPage<T> page 翻页对象
Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper

编码:

@Override
public List<UserInfo> selectPage(Integer page, Integer limit) {
IPage ipage = this.page(new Page(page,limit),null);
return ipage.getRecords();
}

测试

 

 

所执行的sql

6.SQL分析

在MybatisPlusConfig当中添加配置代码,此配置可以显示SQ语句和运行时间

@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
Properties properties=new Properties();
//开启sql格式化
properties.setProperty("format", "true");
performanceInterceptor.setProperties(properties);
return performanceInterceptor;
}

测试

7.代码生成器

1.添加依赖

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

2.添加模板依赖

MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,项目中使用的是Freemarker,我们以Freemarker为例。

<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>

3.编写配置类

设置存放路径,作者

GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
System.out.println(projectPath);
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("itheima");
gc.setOpen(false);

数据源配置

DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql:///test");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);

包配置

PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.jinrui");
mpg.setPackageInfo(pc);

其他配置

// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
// 下划线驼峰命名转换
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// 开启lombok
strategy.setEntityLombokModel(true);
// 开启RestController
strategy.setRestControllerStyle(true);
// 公共父类
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
//@RequestMapping中驼峰转字符串
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();

7.测试

执行main方法,输入模块名和表名:

成功生成代码

8.Demo

 

9.fir项目

1.fir-db

1.实体类添加注解,以MetricData为例,用于数据库表与实体类、字段与属性对应

@TableName("metric_data")
public class MetricData implements Serializable {
private static long serialVersionUID = -2449909017343874495L;
@TableId(value = "mdid", type = IdType.AUTO)
private Long id;
@TableField("metricid")
private String metricId;
@TableField("time")
private Long time;
@TableField("data")
private Double data;
@TableField("addtime")
private Date addtime;
@TableField("reporttime")
private Long reportTime;
@TableField(exist = false)
private Metric metric;
@TableLogic(value = "0", delval = "1")
@TableField("disabled")
private Integer disabled;

2.Mapper层继承BaseMapper,可以调用mp提供的API

public interface MetricDataRepository extends BaseRepository<MetricData, Long>{}
public interface BaseRepository<T, ID extends Serializable> extends BaseMapper<T>()

3.Service层继承Iservice,可以调用mp提供的API

public interface MetricDataService extends BaseService<MetricData>{}
public interface BaseService<T> extends IService<T>{}

4.使用了自定义通用Service类,定义了一些常用的方法,方便复用

public interface BaseService<T> extends IService<T>
{
AdminUser getCurrentAdmin();
User getCurrentUser();
SearchResult findBySearchRequest( SearchRequest searchRequest);
List<T> findAll();
T findById( Serializable id);
boolean deleteById( Serializable p0);
boolean isDisabled();
}

5.MybatisPlusConfig中写了一些配置,用于配置分页插件和SQL分析插件

@Configuration
public class MybatisPlusConfig {
/**
* mybatis-plus分页插件
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor= new PaginationInterceptor();
paginationInterceptor.setDialectType("mysql");
return paginationInterceptor;
}
/**
*sql执行效率插件
* @return
*/
@Bean
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
Properties properties=new Properties();
//开启sql格式化
properties.setProperty("format", "true");
performanceInterceptor.setProperties(properties);
return performanceInterceptor;
}
}

6.条件查询的构造方式

Controller层,attribute(字段)、operator(操作)、values(值)封装到Condition中,col(字段)、direction(方向)封装到Ordering中,然后把这些数据封装到SearchRequest中。

Service层,调用BaseService中的findBySearchRequest方法进行分页查询,迭代构造条件,最后返回SearchResult。

例:Controller层:封装Condition、Ordering、page、limit到SearchRequest,以searchRequest为参数调用service中的search()。

这里面封装数据的SearchRequest,代码如下图所示。

Service层:调用BaseService类中的findBySearchRequest方法用于分页查询。

返回结果SearchResult,代码如图所示。

BaseService中findBySearchRequest方法,主要用于分页,调用contructWrapper方法构造条件。

BaseService中contructWrapper方法用于迭代构造查询条件,调用addCondition方法。

addCondition方法:主要用于匹配操作名称和构造条件。

private QueryWrapper addCondition(String attribute, String operator, List<Object> valuesList, QueryWrapper queryWrapper) {
Object value = null;
if (CollectionUtils.isNotEmpty(valuesList)) {
value = valuesList.get(0);
}
switch (OperatorEnum.matchValue(operator)) {
case LIKE: {
queryWrapper.like(attribute, value);
break;
}
case LIKE_BEGIN: {
queryWrapper.likeRight(attribute, value);
break;
}
case LIKE_END: {
queryWrapper.likeLeft(attribute, value);
break;
}
case GT: {
queryWrapper.gt(attribute, value);
break;
}
case GTE: {
queryWrapper.ge(attribute, value);
break;
}
case EQ: {
queryWrapper.eq(attribute, value);
break;
}
case LT: {
queryWrapper.lt(attribute, value);
break;
}
case LTE: {
queryWrapper.le(attribute, value);
break;
}
case ISNULL: {
queryWrapper.isNull(attribute);
break;
}
case ISNOTNULL: {
queryWrapper.isNotNull(attribute);
break;
}
case IN: {
queryWrapper.in(attribute, valuesList);
break;
}
case NE: {
queryWrapper.ne(attribute, value);
break;
}
default: {
throw new SearchException(ServiceExceptionCodeEnum.BADARGUMENT_PARAM.getCode(), "查询操作符不符合");
}
}
return queryWrapper;
}

枚举类,用于选择对应的查询条件。

 

posted @   我所理解的代码  阅读(766)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示