news 2026/4/16 15:51:25

MybatisPlus工具(详细教程)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MybatisPlus工具(详细教程)

基本使用

导入包:

<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency>

数据源配置:

spring: datasource: driver-class-name: com.mysql.jdbc.Driver # 如果使用 MySQL8 驱动不同,增加时区的配置 serverTimezone=GMT%2B8 url: jdbc:mysql://xx:3306/数据库?useSSL=false&useUnicode=true&characterEncoding=utf-8 username: root password: 123456 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 默认日志 mapper-locations: classpath:/mapper/**/*.xml

基本使用:

启动类增加扫描mapper文件夹,省略@mapper注解

@MapperScan("指定Mapper接口所在的包")

mapper层编写

@Repository // 持久层 public interface BillMapper extends BaseMapper<Bill> {}

service层编写

需要继承IService

public interface BillService extends IService<Bill> {}

service实现类编写

@Service public class BillServiceImpl extends ServiceImpl<BillMapper, Bill> implements BillService {}

常用注解

TableName

实体对应表名

@TableName("wms_ware_info")

TableId

主键注解

@TableId(value = "bid",type = IdType.AUTO)

type类型常见值:

  • AUTO 数据库ID自增
  • NONE 无状态
  • INPUT insert前自行set主键值
  • ASSIGN_ID 雪花算法生产id
  • ASSIGN_UUID UUID
  • ID_WORKER 分布式全局唯一ID,长整型类型,32位UUID字符串
  • ID_WORKER_STR 分布式全局唯一ID 字符串类型

注意:雪花算法:分布式ID生成算法,结果是一个long型的ID

TbaleField

设置实体类中的属性名和字段名注解

@TbaleField("user_name")

# 表中新增字段 create_time,update_time 创建时间/修改时间 @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; # 如果为null,字段也更新为null @TableField(updateStrategy = FieldStrategy.IGNORED) # 表示不是数据库里的字段 @TableField(exist = false) # MyMetaObjectHandler类 @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { // 插入时的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); } // 更新时的填充策略 @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); } }

TableLogic

逻辑删除 (假删除)

// 逻辑删除 value 1:未删除的值 、delval 0 :删除后的值 @TableLogic(value = "1", delval = "0") private Integer isDeleted; // 默认0 未删除 1已删除 # 配置文件 logic-delete-field: flag # 全局逻辑删除的实体字段名 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

通用枚举

设置枚举类、实体字段设置

@Getter public enum SexEnum { MALE(1, "男"), FEMALE(2, "女"); @EnumValue //将注解所标识的属性的值存储到数据库中 private int sex; private String sexName; SexEnum(Integer sex, String sexName) { this.sex = sex; this.sexName = sexName; } } # 实体字段设置 private SexEnum sex; # 配置文件 - 增加配置 # 扫描通用枚举的包 type-enums-package: com.atguigu.mybatisplus.enums

测试

@Test public void test(){ User user = new User(); user.setName("admin"); user.setSex(SexEnum.MALE); // 保持数据库是key值 int result = userMapper.insert(user); }

基本API

Mapper层

// 1. 查询全部数据 List<Emp> emps = empMapper.selectList(null); // 2. 新增 Emp emp1 = new Emp(); emp1.setAge(13); int insert = empMapper.insert(emp1); // 3. 删除 int i = empMapper.deleteById(9L); // 参数id // 3.1 批量删除 int i1 = empMapper.deleteBatchIds(Arrays.asList(11L, 10L)); // 3.2 根据条件删除 注:key 是表字段 Map<String,Object> mapdel = new HashMap<>(); mapdel.put("name","修改的"); empMapper.deleteByMap(mapdel); // 4. 修改 Emp emp2 = new Emp(); emp2.setId(12); emp2.setName("修改的"); int i2 = empMapper.updateById(emp2); // 5. 查询 Emp empO = empMapper.selectById(12L); List<Emp> all = empMapper.selectBatchIds(Arrays.asList(1L, 2L)); System.out.println(all); // 5.1 根据查询条件查询,注:key 是表字段 Map<String,Object> map = new HashMap<>(); map.put("name","修改的");map.put("age","13"); List<Emp> bills = empMapper.selectByMap(map);

Service层

// 1.查出总记录数 long count = empService.count(); // long count2 = empService.count(new QueryWrapper<Emp>()); System.out.println(count); // 2.根据主键id查询 Emp byId = empService.getById(3L); // 3.查询全部 List<Emp> all = empService.list(); // List<Emp> all2 = empService.list(new QueryWrapper<Emp>()); System.out.println(all); // 4.新增 empService.save(new Emp()); // 5.修改 empService.updateById(new Emp()); // empService.update(new QueryWrapper<Emp>()); // 6.新增或修改 , 有主键代表修改,否则新增 empService.saveOrUpdate(new Emp()); // 7.批量新增 List<Emp> alls = Arrays.asList( new Emp("王1", 1), new Emp("琳2", 33), new Emp("凯3", 32)); boolean b = empService.saveBatch(alls); // 8.批量新增或修改 , 有主键代表修改,否则新增 empService.saveOrUpdateBatch(alls); // 9.根据主键 删除 empService.removeById(20L); empService.remove(new QueryWrapper<Emp>()); // 10.批量删除 empService.removeBatchByIds(Arrays.asList(11L, 10L));

条件构造器

Wrapper介绍:

Wrapper 条件构造抽象类

AbstractWrapper 用于查询条件封装,生成 sql 的 where 条件

  • QueryWrapper 查询条件封装
  • UpdateWrapper 修改条件
  • AbstractLambdaWrapper 使用Lambda 语法,它还有LambdaQueryWrapper 、LambdaUpdateWrapper
QueryWrapper:

查询条件

//查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息 QueryWrapper<User> q = new QueryWrapper<>(); q.like("username","a").between("age",20,30).isNotNull("email"); //排序条件 orderByDesc 降序 orderByAsc 升序 q.orderByDesc("age").orderByAsc("id"); List<User> users = userMapper.selectList(q); users.forEach(System.out::println);

删除条件

QueryWrapper<User> q = new QueryWrapper<>(); q.isNull("email"); int result = userMapper.delete(q); System.out.println(result > 0 ? "删除成功!" : "删除失败!");

条件的优先级

QueryWrapper<User> q = new QueryWrapper(); q.select("bill_name","bill_num","pay"); // select查询 只显示这几个字段,其他字段不显示 // ge 大于等于 gt 大于 le 小于等于 lt 小于 eq 等于 ne 不等 // between 范围 notBetween in notIn // like notLike likeLeft (LIKE '%值’) likeRight (LIKE’值%’) // isNull isNotNull // inSql 字段IN ( sql语句) notInSql // groupBy 分组 orderByAsc orderByDesc orderBy 例:orderBy(true,true,“id”,“name”)—–>order by id ASC, name ASC // having exists notExists or and q.gt("bill_num",4) .and(i->{ i.like("bill_name","a").or().isNull("pay"); }).isNull("pay"); List<Map<String, Object>> maps = userMapper.selectMaps(q);

子查询

QueryWrapper<User> q = new QueryWrapper<>(); q.inSql("uid", "select uid from 表 where uid <= 100"); List<User> list = userMapper.selectList(q);

UpdateWrapper:

UpdateWrapper<User> u = new UpdateWrapper<>(); u.like("username","a") .set("email","修改的字段").set("bill_name","修改的字段2"); int result = userMapper.update(null, u); System.out.println(result > 0 ? "修改成功!" : "修改失败!");

condition:

String a = "a"; Integer b = null; Integer c = 30; QueryWrapper<User> q = new QueryWrapper<>(); // 参数 1 boolean值,满足条件会执行 q.like(StringUtils.isNotBlank(a), "user_name", a) .ge(b != null, "age", b) .le(c != null, "age", c); List<User> list = userMapper.selectList(q);

LambdaQueryWrapper:

String a = "a"; Integer b = null; Integer c = 30; LambdaQueryWrapper<User> q = new LambdaQueryWrapper<>(); q.like(StringUtils.isNotBlank(a), User::getName, a) .ge(b != null, User::getAge, b) .le(c != null, User::getAge, c); List<User> list = userMapper.selectList(q);

LambdaUpdateWrapper:

LambdaUpdateWrapper<User> u = new LambdaUpdateWrapper<>(); u.like(User::getName, "a").isNull(User::getEmail)); u.set(User::getName, "小黑").set(User::getEmail,"xxx"); int result = userMapper.update(null, u);

常用插件

分页

配置类

@Configuration @MapperScan("com.yan.mybatis.mapper") public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件 - 指向数据库类型 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

测试

@Test public void test1(){ // 参数:当前页、显示条数、查询条件 Page<Bill> page = billMapper.selectPage(new Page<>(1, 5), null); List<Bill> users = page.getRecords(); users.forEach(System.out::println); System.out.println(page.getRecords()); // 获取记录数 System.out.println(page.getSize()); // 获取显示条数 System.out.println(page.getCurrent()); // 获取当前页的页码 System.out.println(page.getPages()); // 获取总页码 System.out.println(page.getTotal()); // 获取总记录数 boolean b1 = page.hasNext(); // 是否有下一页 boolean b2 = page.hasPrevious(); // 是否有上一页 }

自定义分页

# Mapper层定义 Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age); # XMl定义 <select id="selectPageVo" resultType="User"> select * from t_user where age > #{age} </select> # 测试 Page<User> page = userMapper.selectPageVo(new Page<User>(1,2), 20); List<User> users = page.getRecords();

乐观锁

乐观锁:保持乐观状态,无论干什么都不会上锁,如果有问题就再次更新值测试。(版本号version)

悲观锁:总是认为总会出现问题,无论干什么都会上锁后再去操作。

配置类

@Configuration @MapperScan("com.yan.mybatis.mapper") public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加分页插件 - 指向数据库类型 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //添加乐观锁插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }

实体字段增加注解

@Version // 标识乐观锁版本号字段 private String version;

测试

@Test public void test1(){ // 1.B1 获得的值 Bill b1 = billMapper.selectById(16); System.out.println("B1 :" + b1.getMoney()); // 2.B2 获得的值 Bill b2 = billMapper.selectById(16); System.out.println("B2 :" + b1.getMoney()); // 3.B1 获得的值 + 50 b1.setMoney(b1.getMoney() + 50); billMapper.updateById(b1); // 4.B2 获得的值 - 30 b2.setMoney(b2.getMoney()-30); int result = billMapper.updateById(b2); if (result == 0) { // 操作失败,重试 Bill b = billMapper.selectById(16); b.setMoney(b.getMoney() - 30); billMapper.updateById(b); } // 5.查看 16这条数据 值 - 乐观锁 Bill bill = billMapper.selectById(16); System.out.println("Bill :" + bill.getMoney()); }

注意:

整数类型下 newVersion = oldVersion + 1 newVersion 会回写到 entity 中 仅支持 updateById(id) 与 update(entity, wrapper) 方法 在 update(entity, wrapper) 方法下, wrapper 不能复用

通用枚举

枚举类

import com.baomidou.mybatisplus.annotation.EnumValue; import lombok.Getter; /** * 枚举 */ @Getter public enum SexEnum { ONE(0, "未付款"), TWO(1, "已付款"); @EnumValue // 将注解所标识的属性的值存储到数据库中 private int index; private String name; SexEnum(Integer index, String name) { this.index = index; this.name = name; } }

配置文件需要配置

type-enums-package: cn.good.yan.pojo.conf

实体需要引用

private SexEnum pay;

代码生成器

导入依赖包

<!-- 代码生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency>

测试

// 代码生成器 public static void main(String[] args) { FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8", "用户名", "密码") .globalConfig(builder -> { builder.author("yan") // 设置作者 // .enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir("G://xx"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.yan") // 设置父包名 .moduleName("mybatis") // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "G://xx/mapper")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("pms_spu_comment") // 设置需要生成的表名 .addTablePrefix("t_", "pms_"); // 设置过滤表前缀 }) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .templateEngine(new FreemarkerTemplateEngine()) .execute(); }

多数据库

适用场景:读写分离、一主一从、多库

导入依赖包

<!-- 多数据源 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.5.0</version> </dependency>

更改配置

spring: datasource: # 配置多数据源 dynamic: # 设置默认的数据源或者数据源组,默认值即为master primary: master # 严格匹配数据源,默认false 如:true未匹配到指定数据源时抛异常,false使用默认数据源,也就是主数据源 strict: false datasource: master: url: jdbc:mysql://127.0.0.1:3306/数据库1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver username: 用户名 password: 密码 slave: url: jdbc:mysql://127.0.0.1:3306/数据库2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver username: 用户名 password: 密码

指定操作数据源

// 指定操作的数据源,master - 也可以放在具体的方法上,和类上,就近原则取对应的数据源 @DS("master") public interface UserService extends IService<User> {} // --- @DS("slave") public interface BillService extends IService<Bill> {}

测试

@Autowired private BillService billService; @Autowired private UserService userService; @Test public void test(){ Bill b1 = billService.getById(16); System.out.println(b1); User u1 = userService.getById(2); System.out.println(u1); }

MyBatisX插件

MyBatisX一款基于 IDEA 的快速开发插件,简化我们开发。在IDEA的插件里进行下载MyBatisX。

IDEA中与数据库建立链接:

找到我们要生成的表

然后点击,填写第一页

填写第二页

操作完成 - 快速生成对应的文件

然后我们开发过程中快速生成CRUD操作:

选择这个,可以快速生产对应的代码和XML映射文件

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:02:21

一箭双雕:如何用结构化数据打造SEO与AI都能理解的“通用语言”

你可以写出优秀内容&#xff0c;却仍然难以被注意到&#xff0c;这全是因为机器并不总是理解你发布的内容。 结构化数据通过为页面添加意义和上下文来解决这个问题。它帮助搜索引擎和人工智能模型&#xff0c;如ChatGPT、Claude、Perplexity、谷歌的AI概览和AI模式等&#xff…

作者头像 李华
网站建设 2026/4/16 2:33:01

传统仓库盘点耗时耗力且账实不符,如何实现实时动态库存管理?

谢邀。传统仓库盘点耗时耗力且账实不符&#xff0c;如何实现实时动态库存管理&#xff1f; 很多企业在做仓库管理时都会遇到同一个困扰&#xff1a;盘点永远很累&#xff0c;库存总是对不上账。 你可能经历过这样的场景&#xff1a; 一个月一次全盘点&#xff0c;仓管忙得团…

作者头像 李华
网站建设 2026/4/16 13:44:16

Java AI Skills 诞生:从“盲目对话”到“有组织的行为模式”

在 AI Agent 的工程化道路上&#xff0c;开发者们往往会经历从兴奋到困惑的过程。最初&#xff0c;我们惊叹于大模型能通过 Function Call 调用一个简单的 getMessage(String id) 函数&#xff1b;但很快&#xff0c;在构建复杂的企业级应用时&#xff0c;我们会发现&#xff1…

作者头像 李华
网站建设 2026/4/16 1:34:48

社保卡照片怎么压缩?社保卡制卡证件照要求全解

社保卡申领、制卡上传照片时&#xff0c;很多人都卡在了照片环节&#xff1a;要么照片体积过大提交失败&#xff0c;要么手动改尺寸后比例失调&#xff0c;找工具压缩又怕画质变差&#xff0c;反复调整还是通不过社保系统的审核。社保卡制卡照片有明确的官方规格&#xff1a;背…

作者头像 李华
网站建设 2026/4/16 15:19:43

RK3568平台YOLOv11模型部署教程:环境配置与端侧推理优化全流程解析

文章目录 【深度实战】RK3568平台YOLO11模型从零到部署完整指南 前言 技术架构概览 一、开发环境搭建 1.1 Anaconda环境配置 1.2 RKNN工具链安装 下载核心组件 安装依赖和工具包 1.3 PyTorch环境配置 二、数据集准备与标注 2.1 数据集结构设计 2.2 图像标注工具配置 标注操作流…

作者头像 李华