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

【Mybatis-Plus】使用步骤 条件构造器 分页模型

文章目录

  • Mybatis-Plus
    • 使用步骤
    • 条件构造器
    • 分页模型

Mybatis-Plus

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

  • 需要快速搭建 CRUD 接口的应用程序。
  • 对于已有使用 MyBatis 的项目,希望通过最小改动获得更好的开发效率。
  • 在不牺牲灵活性的前提下,寻求一种更高效的方式来处理常见的数据库操作。
  • 需要简单而强大的分页、排序等高级功能。
  • 关注安全性,尤其是防止 SQL 注入攻击的应用。

简介 | MyBatis-Plus

使用步骤

新建 SpringBoot 项目,项目结构如下:
在这里插入图片描述

1、Maven 依赖配置

<!-- Mybatis-Plus包 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

其他必要的包

<!-- MySQL驱动包 -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- lombok包 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

2、应用配置文件

配置 MyBatis-Plus 相关属性,如类型别名包路径、控制台打印 SQL 语句、是否开启驼峰映射等

mybatis-plus:
  type-aliases-package: com.hz.pojo #类型别名所在的包
  #控制台打印sql语句
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: false # 关闭驼峰映射

3、实体类定义

创建一个实体类 Provider,对应数据库中的 smbms_provider

使用 MyBatis-Plus 注解来指定主键策略和字段映射

@Data
@TableName("smbms_provider")
public class Provider implements Serializable {
	// 数据库自增 ID 作为主键
	@TableId(value = "id", type = IdType.AUTO)
	private Integer id;   //id
	private String proCode; //供应商编码
	// 映射到数据库字段 proName as pname
	@TableField("proName")
	private String pname; //供应商名称
	private String proDesc; //供应商描述
	private String proContact; //供应商联系人
	private String proPhone; //供应商电话
	private String proAddress; //供应商地址
	private String proFax; //供应商传真
	private Integer createdBy; //创建者
	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
	private Date creationDate; //创建时间
	private Integer modifyBy; //更新者
	private Date modifyDate;//更新时间
	// 忽略此字段
	@TableField(exist = false)
	private String abc; //冗余字段
}

4、SpringBoot 应用启动类

定义应用程序的入口点,并扫描 Mapper 接口的位置

@SpringBootApplication
@MapperScan("com.hz.mapper")
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }

}

ProviderMapper 继承 BaseMapper<Provider> 并生成单元测试(快捷键 Alt + Enter)

public interface ProviderMapper extends BaseMapper<Provider> {}
@SpringBootTest
public class ProviderMapperTest {
    @Resource
    private ProviderMapper providerMapper;
    @Test
    public void findById(){
        // Provider provider = providerMapper.selectById(1);
        providerMapper.selectList(null);
    }
}

查看控制台 SQL 代码及查询结果

JDBC Connection [HikariProxyConnection@529893402 wrapping com.mysql.cj.jdbc.ConnectionImpl@17b016ac] will not be managed by Spring
==>  Preparing: SELECT id,proCode,proName AS pname,proDesc,proContact,proPhone,proAddress,proFax,createdBy,creationDate,modifyBy,modifyDate FROM smbms_provider
==> Parameters: 
<== ......

去到 BaseMapper 的源码里

/**
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 * <p>这个 Mapper 支持 id 泛型</p>
 *
 * @author hubin
 * @since 2016-01-23
 */
public interface BaseMapper<T> extends Mapper<T> {...}

接口覆盖了大部分单表操作的常用方法:

插入操作

  • insert 插入一个实体对象到数据库中。

删除操作

  • deleteById 根据主键 ID 删除对应的数据库记录
  • deleteByMap 根据传入的列名和列值对删除记录
  • delete 根据条件构造器删除记录
  • deleteBatchIds 根据主键 ID 集合批量删除记录

更新操作

  • updateById 根据主键 ID 更新实体对象
  • update 根据条件构造器更新实体对象

查询操作

  • selectById 根据主键 ID 查询实体对象
  • selectBatchIds 根据主键 ID 集合批量查询实体对象列表
  • selectByMap 根据列名和列值对查询实体对象列表
  • selectOne 根据条件构造器查询一条记录
  • selectCount 根据条件构造器查询符合条件的记录数
  • selectList 根据条件构造器查询实体对象列表
  • selectMaps 根据条件构造器查询记录,结果以 Map<String, Object> 形式返回
  • selectObjs 根据条件构造器查询记录,但只返回第一个字段的值

分页查询操作

  • <E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper); 根据条件构造器进行分页查询,返回实体对象列表
  • <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper); 根据条件构造器进行分页查询,结果以 Map<String, Object> 形式返回

加入 Service 层接口及实现类,项目结构改变如下:

在这里插入图片描述

5、服务层

定义服务层接口 ProviderService 继承 IService<Provider>,并在实现类 ProviderServiceImpl 中扩展 ServiceImpl<ProviderMapper, Provider>

public interface ProviderService extends IService<Provider> {}

@Service
public class ProviderServiceImpl extends ServiceImpl<ProviderMapper, Provider> implements ProviderService {}

BaseMapper 是 MyBatis-Plus 提供的一个基础映射器接口,它直接对应于 MyBatis 的 Mapper 接口。它主要用于定义和实现单表的基础 CRUD 操作。BaseMapper 的方法大多数是直接对应 SQL 语句的,如 insertdeleteByIdupdateById 等。

IService 是 MyBatis-Plus 提供的一个服务接口,它定义了一系列的业务服务方法。它主要用于实现业务逻辑,可以包含单表或多表的复杂操作。IService 通常会使用 BaseMapper 来执行底层的数据库操作。

去到 IServiceServiceImpl 的源码里

/**
 * 顶级 Service
 *
 * @author hubin
 * @since 2018-06-23
 */
public interface IService<T> {...}
/**
 * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 )
 *
 * @author hubin
 * @since 2018-06-23
 */
@SuppressWarnings("unchecked")
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {...}

IService 接口中一些关键方法:

插入操作

  • boolean save(T entity) 插入一个实体对象到数据库
  • boolean saveBatch(Collection<T> entityList) 批量插入实体对象集合
  • boolean saveOrUpdate(T entity) 依据实体ID存在与否,插入或更新实体

删除操作

  • boolean removeById(Serializable id) 根据主键ID删除记录
  • boolean removeByMap(Map<String, Object> columnMap) 根据条件Map删除记录
  • boolean remove(Wrapper<T> queryWrapper) 根据条件包装器删除记录
  • boolean removeByIds(Collection<?> list) 根据ID集合批量删除记录

更新操作

  • boolean updateById(T entity) 根据实体主键更新记录
  • boolean update(T entity, Wrapper<T> updateWrapper) 根据条件和实体更新记录
  • boolean updateBatchById(Collection<T> entityList) 根据实体集合批量更新记录

查询操作

  • T getById(Serializable id) 根据主键ID查询实体
  • List<T> listByIds(Collection<? extends Serializable> idList) 根据ID集合查询实体列表
  • List<T> listByMap(Map<String, Object> columnMap) 根据条件Map查询实体列表

6、编写单元测试

通过 QueryWrapper 及其内置的方法构建复杂查询条件

@SpringBootTest
public class ProviderServiceImplTest {
    @Resource
    private ProviderService providerService;
    @Test
    public void find() {
        // 创建 QueryWrapper 实例
        QueryWrapper<Provider> queryWrapper = new QueryWrapper<>();
        // 选择要查询的列
        queryWrapper.select("id", "proCode", "proDesc", "proName");
        // 构建查询条件
        // 注意:MyBatis-Plus 的 like 和 eq 方法可以传递 condition 参数实现动态 SQL
        queryWrapper.like("proDesc", "深圳");
        queryWrapper.eq("proCode", "GZ_GYs002");
        // 添加排序条件
        queryWrapper.orderByDesc("creationDate");
        // 执行查询并获取结果列表
        List<Provider> providerList = providerService.list(queryWrapper);
    }
}
providerService.list(new QueryWrapper<Provider>()
                     .select("id","proCode","proDesc","proName")
                     .like(true,"proDesc","深圳")
                     .eq(true,"proCode","GZ_GYS002")
                     .orderByDesc("creationDate"));

执行结果如下:

JDBC Connection [HikariProxyConnection@1478493964 wrapping com.mysql.cj.jdbc.ConnectionImpl@34208baa] will not be managed by Spring
==>  Preparing: SELECT id,proCode,proDesc,proName FROM smbms_provider WHERE (proDesc LIKE ? AND proCode = ?) ORDER BY creationDate DESC
==> Parameters: %深圳%(String), GZ_GYs002(String)
<== Total: 0

条件构造器

MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。

在 MyBatis-Plus 中,Wrapper 类是构建查询和更新条件的核心工具。以下是主要的 Wrapper 类及其功能:

  • AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。
  • QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用 andor 逻辑。
  • UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
  • LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
  • LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。

UpdateWrapper

@Test
    public void update(){
        Provider provider = new Provider();
        provider.setId(22L);
        provider.setPname("张三公司");
        providerService.updateById(provider);
    }

根据供应商ID id 修改供应商名称 pname

@Test
public void update(){
    Provider provider = new Provider();
    provider.setPname("张三公司");
    providerService.update(provider,
        new UpdateWrapper<Provider>().eq("proCode","zhangsan"));
}

根据供应商编码 proCode 修改供应商名称 pname

LambdaQueryWrapper

@Test
public void find(){
    LambdaQueryWrapper<Provider> providerLambdaQueryWrapper = Wrappers.lambdaQuery();
    providerLambdaQueryWrapper.select(Provider::getPname,Provider::getId);
    providerLambdaQueryWrapper.eq(Provider::getPname,"张三公司");
    providerService.list(providerLambdaQueryWrapper);
}

根据供应商名称 pname 查询指定字段

分页模型

使用简单分页模型

Page<T> 实现接口 IPage<T>,是用来表示分页数据的通用工具类。

public class Page<T> implements IPage<T> {
    private static final long serialVersionUID = 8545996863226528798L;
    protected List<T> records;
    protected long total;
    protected long size;
    protected long current;
    protected List<OrderItem> orders;
    protected boolean optimizeCountSql;
    protected boolean isSearchCount;
    protected boolean hitCount;
    protected String countId;
    protected Long maxLimit;

    public Page() {
        this.records = Collections.emptyList(); // 查询数据列表
        this.total = 0L; // 默认总记录数为0
        this.size = 10L; // 默认每页显示10条记录
        this.current = 1L; // 默认当前页是第1页
        this.orders = new ArrayList(); // 表示没有排序规则
        this.optimizeCountSql = true;
        this.isSearchCount = true;
        this.hitCount = false;
    }
	......
}
@Configuration
public class MybatisPlusConfig {
    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 如果配置多个插件, 切记分页最后添加
        // 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
        return interceptor;
    }
}
  • MybatisPlusInterceptor 对象是 MyBatis-Plus 用于拦截 SQL 执行的拦截器。

  • PaginationInnerInterceptor 是 MyBatis-Plus 提供的分页插件。

  • DbType.MYSQL 指定了数据库类型为 MySQL,这样分页插件会根据 MySQL 的特性生成相应的分页 SQL。

@Test
public void findSize(){
    Page<Provider> page = new Page<>(2,5);
    providerService.page(page,null);

    List<Provider> providers = page.getRecords();//获得分页数据
    System.out.println("总记录数: " + page.getTotal());//总记录数
    System.out.println("当前页: " + page.getCurrent());//当前页
    System.out.println("总页数: " + page.getPages());//总页数
    System.out.println("是否有上一页: " + page.hasPrevious());//是否有上一页
    System.out.println("是否有下一页: " + page.hasNext());//是否有下一页
}

创建 Page 对象并指定当前页码(2)和每页显示的记录数(5);调用 providerService.page(page, null) 方法执行分页查询,其中第一个参数是分页对象,第二个参数是查询条件;从Page对象中获取分页数据和相关信息。


http://www.kler.cn/a/448400.html

相关文章:

  • 砂轮磨料基础知识及发展学习笔记
  • 探索 Seaborn Palette 的奥秘:为数据可视化增色添彩
  • 【jvm】主要参数
  • tslib(触摸屏输入设备的轻量级库)的学习、编译及测试记录
  • 使用 AI 辅助开发一个开源 IP 信息查询工具:一
  • Leetcode Hot 100 【二叉树】104. 二叉树的最大深度
  • Flink 简介和简单的demo
  • Linux -- 线程控制相关的函数
  • 判断实例化或推断的时机
  • 东方财富股吧发帖与评论爬虫
  • 【多维DP】力扣3122. 使矩阵满足条件的最少操作次数
  • CTF知识集-文件上传
  • 联合物种分布模型(JSDM)与Hmsc包:群落生态学数据分析与预测技术
  • Android adb查看某个进程的总线程数
  • C语言的指针和java的引用有什么区别?
  • 3 需求分析
  • Windows装Docker至D盘/其他盘(最新,最准确,直接装)
  • 【Linux】常用命令大全
  • ubuntu 安装更新 ollama新版本
  • 网络地址转换NAT
  • DeepFaceLab技术浅析(三):自编码器模块
  • 浏览器对JSON格式数据的支持【超详解】
  • #渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍04-盲SQL注入(Blind SQL Injection)
  • upload-labs靶场保姆级攻略
  • Python使用队列加多线程处理数据
  • SSM 医院预约挂号系统 Vue 实现:开启智能医疗新征程