MyBatis-Plus精讲和使用注意事项

news/2024/11/20 12:31:22/

🍓 简介:java系列技术分享(👉持续更新中…🔥)
🍓 初衷:一起学习、一起进步、坚持不懈
🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏
🍓 希望这篇文章对你有所帮助,欢迎点赞 👍 收藏 ⭐留言 📝

🍓 更多文章请点击
在这里插入图片描述在这里插入图片描述

文章目录

  • 一、 Mybatis-Plus是什么?
  • 二、Mybatis和Mybatis-Plus区别
  • 三、快速入门
    • 3.1 创建user表结构
    • 3.2 新建Boot项目
    • 3.3 添加配置
    • 3.4 新建对应实体类
    • 3.5 测试
    • 3.6 控制台输出
  • 四、开启日志SQL可见
  • 五、CRUD
    • 5.1 Mapper-数据操作层
    • 5.2 Service – 业务逻辑层
    • 5.3 实现类
  • 六、条件构造器Wrapper
  • 七、分页插件
    • 7.1 分页查询测试(有问题)
    • 7.2 增加分页拦截器配置(成功)
    • 7.3 Page对象
  • 八、查询编写
    • 8.1 条件查询的3种格式
      • 8.1.1 第一种 (不推荐)
      • 8.1.2 第二种 Lambda 表达式
      • 8.1.3 第三种 `直接使用LambdaQueryWrapper`(推荐)
    • 8.2 查询条件null值处理
    • 8.3 查询部分属性
    • 8.4 查询未定义的属性
  • 九、常用注解使用(配置映射关系)
    • 9.1 @TableName 表名映射
    • 9.2 @TableField 字段映射
    • 9.3 @TableId 主键类型
    • 9.1 @Version 乐观锁
    • 9.1 @TableLogic 逻辑删除
  • 十、全局配置

一、 Mybatis-Plus是什么?

官方文档地址 :https://www.baomidou.com/

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增

强不做改变,为简化开发、提高效率而生。

MybatisPlus可以节省大量时间,所有的CRUD代码都可以自动化完成

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

在这里插入图片描述

二、Mybatis和Mybatis-Plus区别

MyBatis:

  1. 所有SQL语句全部自己写
  2. 手动解析实体关系映射转换为MyBatis内部对象注入容器
  3. 不支持Lambda形式调用
  4. 驼峰(属性)和下划线(字段)的映射关系 mybatis中默认是关闭的。

Mybatis Plus:

  1. 强大的条件构造器,满足各类使用需求
  2. 内置的Mapper,通用的Service,少量配置即可实现单表大部分CRUD操作
  3. 支持Lambda形式调用
  4. 提供了基本的CRUD功能,连SQL语句都不需要编写
  5. 自动解析实体关系映射转换为MyBatis内部对象注入容器
  6. 驼峰(属性)和下划线(字段)的映射关系Mybatis-Plus中 默认是开启的 ,不需要额外配置。

三、快速入门

我们将通过一个简单的 Demo 来阐述 MyBatis-Plus 的强大功能

3.1 创建user表结构

idnameageemail
1Jone18test1@baomidou.com
2Jack20test2@baomidou.com
3Tom28test3@baomidou.com
4Sandy21test4@baomidou.com
5Billie24test5@baomidou.com

创建表结构


DROP TABLE IF EXISTS user;CREATE TABLE user
(id BIGINT(20) NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',age INT(11) NULL DEFAULT NULL COMMENT '年龄',email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (id)
);

新增数据

DELETE FROM user;INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

结果展示

在这里插入图片描述

3.2 新建Boot项目

引用spring boot starter 父工程

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.1</version><relativePath/></parent>

引入对应依赖这里使用mysql数据库

<dependencies><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>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.11</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

3.3 添加配置

在 application.yml 配置文件中添加 mysql 数据库的相关配置:

spring:# 数据源配置datasource:# 数据库连接信息配置datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql:///test_demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true&failOverReadOnly=falseusername: rootpassword: root

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:

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

3.4 新建对应实体类

@Data
public class User {private Long id;private String name;private Integer age;private String email;
}

编写 Mapper 包下的 UserMapper接口
继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能

//@Mapper  没有没配@MapperScan的需添加@Mapper注解
public interface UserMapper extends BaseMapper<User> {}

3.5 测试

@SpringBootTest
public class SampleTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelect() {System.out.println(("----- selectAll method test ------"));List<User> userList = userMapper.selectList(null);Assert.assertEquals(5, userList.size());userList.forEach(System.out::println);}
}

UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件

3.6 控制台输出

在这里插入图片描述

四、开启日志SQL可见

mybatis-plus:configuration:# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

sql可见
在这里插入图片描述

五、CRUD

方法非常多,我简单列出几个,具体请查看官方文档中的接口链接:接口文档

// 插入一条记录
int insert(T entity);// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

5.1 Mapper-数据操作层

继承BaseMapper接口

public interface UserDao extends BaseMapper<TestUser> {}

5.2 Service – 业务逻辑层

继承IService接口

public interface UserService extends IService<User> {}

5.3 实现类

继承ServiceImpl实现UserService 接口

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

六、条件构造器Wrapper

条件构造文档链接

AbstractWrapper
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类

用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件

注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

在这里插入图片描述

七、分页插件

7.1 分页查询测试(有问题)

@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectPage(){Page<User> page = new Page<>(1,2);Page<User> result = userMapper.selectPage(page, null);System.out.println("当前页码"+result.getCurrent());System.out.println("每页数量"+result.getSize());System.out.println("数据总数"+result.getTotal());System.out.println("当前页数据"+result.getRecords());}
}

发现分页未生效
在这里插入图片描述

7.2 增加分页拦截器配置(成功)

@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor pageInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mybatisPlusInterceptor;}
}

在这里插入图片描述

7.3 Page对象

该类继承了 IPage 类,实现了 简单分页模型 如果你要实现自己的分页模型可以继承 Page 类或者实现 IPage 类

属性名类型默认值描述
recordsListemptyList查询数据列表
totalLong0查询列表总记录数
sizeLong10每页显示条数,默认 10
currentLong1当前页
ordersListemptyList排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本
optimizeCountSqlbooleantrue自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false
optimizeJoinOfCountSqlbooleantrue自动优化 COUNT SQL 是否把 join 查询部分移除
searchCountbooleantrue是否进行 count 查询,如果指向查询到列表不要查询总记录数,设置该参数为 false
maxLimitLong单页分页条数限制
countIdStringxml 自定义 count 查询的 statementId

八、查询编写

8.1 条件查询的3种格式

8.1.1 第一种 (不推荐)

@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectPage(){//查询年龄大于5岁小于20岁的用户//构造条件QueryWrapper<User> qw = new QueryWrapper<>();qw.lt("age",20);qw.gt("age",5);List<User> userList = userMapper.selectList(qw);System.out.println(userList);}
}

结果成功 缺点:字段名容易写错

在这里插入图片描述

8.1.2 第二种 Lambda 表达式

@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectPage(){//查询年龄大于5岁小于20岁的用户//构造条件QueryWrapper<User> qw = new QueryWrapper<>();qw.lambda().lt(User::getAge,20).gt(User::getAge,5);List<User> userList = userMapper.selectList(qw);System.out.println(userList);}
}

结果成功,但是每次都需要.lambda()
在这里插入图片描述

8.1.3 第三种 直接使用LambdaQueryWrapper(推荐)

@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectPage(){//查询年龄大于5岁小于20岁的用户//构造条件LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();qw.lt(User::getAge,20).gt(User::getAge,5);List<User> userList = userMapper.selectList(lqw);System.out.println(userList);}
}

在这里插入图片描述

8.2 查询条件null值处理

由于存在请求参数可能有值或者null的情况,所以要添加判断

表中数据
在这里插入图片描述

@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectNotNull(){//模拟查询条件UserDTO userDTO = new UserDTO();userDTO.setAge(5);userDTO.setAge2(20);//构造条件LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();//链式编程,分开也可以lqw.ge(null!=userDTO.getAge(),User::getAge,userDTO.getAge()).lt(null!=userDTO.getAge2(),User::getAge,userDTO.getAge2());List<User> userList = userMapper.selectList(lqw);System.out.println(userList);}
}

结果

在这里插入图片描述

8.3 查询部分属性


@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectPortion(){//构造条件LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();lqw.select(User::getId,User::getName);List<User> userList = userMapper.selectList(lqw);System.out.println(userList);}
}

在这里插入图片描述

8.4 查询未定义的属性


@SpringBootTest
public class TestPlus {@Autowiredprivate UserMapper userMapper;@Testvoid testSelectPortion2(){//构造条件QueryWrapper<User> lqw = new QueryWrapper<>();lqw.select("count(1) num,age");lqw.groupBy("age");List<Map<String, Object>> maps = userMapper.selectMaps(lqw);System.out.println(maps);}
}

并且别名也能生效
在这里插入图片描述

九、常用注解使用(配置映射关系)

9.1 @TableName 表名映射

  • 描述:表名注解,标识当前实体类与数据库表的对应关系
  • 使用位置:实体类
@TableName("sys_user")
public class User {private Long id;private String name;private Integer age;private String email;
}
属性类型必须指定默认值描述
valueString“”数据库表名
schemaString“”schema
keepGlobalPrefixbooleanfalse是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMapString“”xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMapbooleanfalse是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludePropertyString[]{}需要排除的属性名 @since 3.3.1

9.2 @TableField 字段映射

  1. 设置当前对应数据库表中的字段关系
@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname")private String name;private Integer age;private String email;
}
  1. 数据库中未定义属性
@TableField(exist=false)
private Integer result;

exist:设置属性在数据库表字段中是否存在,默认为true.此属性无法与value合并使用

  1. 密码不想被查询
@TableField(value = "pwd",select = false)
private String password;

select:设置属性是否参与查询,此属性与select()映射配置不冲突

注解属性如下:

属性类型必须指定默认值描述
valueString“”数据库字段名
existbooleantrue是否为数据库表字段
conditionString“”
updateString“”
insertStrategyEnumFieldStrategy.DEFAULT举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategyEnumFieldStrategy.DEFAULT举例:IGNORED update table_a set column=#{columnProperty}
whereStrategyEnumFieldStrategy.DEFAULT举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fillEnumFieldFill.DEFAULT字段自动填充策略
selectbooleantrue是否进行 select 查询
keepGlobalFormatbooleanfalse是否保持使用全局的 format 进行处理
jdbcTypeJdbcTypeJdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)
typeHandlerClass<? extends TypeHandler>UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)
numericScaleString“”指定小数点后保留的位数

9.3 @TableId 主键类型

  • 描述:主键注解
  • 使用位置:实体类主键字段
@TableName("sys_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String name;private Integer age;private String email;
}
属性类型必须指定默认值描述
valueString“”主键字段名
typeEnumIdType.NONE指定主键类型

IdType

描述
AUTO数据库 ID 自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert 前自行 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 方法)
ID_WORKER分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)
UUID32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

9.1 @Version 乐观锁

  1. 第一步 :表中增加乐观锁标记
    在这里插入图片描述2. 实体类中添加对应字段
@Data
public class User {@Versionprivate Integer version;
}
  1. 配置乐观锁拦截器
@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor pageInterceptor(){MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();//分页插件mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());//乐观锁mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;}
}
  1. 使用乐观锁在修改前必须先获取对应version字段数据
  2. 原理
    update user set age = 12 ,version = version +1 where version = ?
    ? 查询出来的version结果

9.1 @TableLogic 逻辑删除

public class User{@TableLogic(value = "0",delval = "1")private Integer isDelete;
}

或者配置文件全局配置

mybatis-plus:global-config:db-config:logic-delete-field: isDelete#逻辑未删除值logic-not-delete-value: 0#逻辑已删除值logic-delete-value: 1

十、全局配置

mybatis-plus:global-config:db-config:#id类型id-type: ASSIGN_ID#数据库表默认前缀table-prefix: tb_

本篇持续更新...........

但是

在这里插入图片描述在这里插入图片描述


http://www.ppmy.cn/news/79385.html

相关文章

让input框只输入英文

解决扫码枪在中文输入法时扫码冲突 扫码枪在扫完码时会自动回车&#xff0c;这时如果是中文输入法就会触发输入法联想&#xff0c;再加一个回车&#xff0c;那么input框输入的就成中文了。如果可以控制input框只能输入英文那就好了。css有一个属性&#xff08;ime-mode&#xf…

draw.io如何绘制带箭头的弧线

好长时间没有写draw.io相关的技巧了。今天再补充一个小技巧。 如何绘制像下图中蓝色的带箭头的弧线&#xff1f; 本来以为这个问题应该很简单&#xff0c;但是在仔细研究了很久之后我发现这个问题并没有想像得那么容易。 众所周知&#xff0c;draw.io中带箭头的线叫作“connect…

网络安全管理员证书有什么用?2023证书怎么考?证书报考条件?

网络安全管理员是做什么工作的呢&#xff1f;现如今&#xff0c;网络高速发展&#xff0c;带动了很多行业的兴起&#xff0c;比如说电商行业&#xff0c;今天已经步入到足不出户即可购物的时代了&#xff0c;当然网络也是一把“双刃剑”&#xff0c;带来了好处的同时&#xff0…

C语言爬取HTML-爬取壁纸 文末附源码

前言&#xff1a;这学期计算机软件课程设计的其中一个题目是使用C语言爬取HTML&#xff0c;本打算使用C语言的CSpidr库来实现&#xff0c;但是因为它的依赖liburi没有找到在哪里安装&#xff0c;所以放弃了这个想法&#xff0c;使用的是curl以及libxml2这两个库&#xff0c;能够…

vue记录鼠标拖拽划过位置并将划过位置变色

首先 我们要做一个这样的基本组件 <template><div><!--循环遍历 List数组用当前下面当做key值然后定义了 onDragStart 鼠标拖动时触发定义 onDragEnd 拖动结束后触发定义 onDragOver 记录所有鼠标拖动经过的位置--><divclass"skeleton"v-f…

聊聊 Milvus GC:从一次数据丢失事件展开

QueryNode 日志中频繁报错&#xff1f;对象存储数据离奇消失[1]&#xff1f; 令人震惊的数据丢失事件就这样发生了&#xff0c;一位来自 BOSS 直聘的 AI 研发工程师无意卷入到此次的风波中&#xff0c;他和 Milvus 社区的伙伴经过层层排查、抽丝剥茧&#xff0c;成功找出了问题…

重磅新书上市,带你看看了不起的芯片!

千呼万唤始出来&#xff0c;我的第一本书《了不起的芯片》今天正式和大家见面啦! 任何一本书的背后都有一段不为人知的曲折故事&#xff0c;在此和大家分享一下我写这本书的心路历程。希望我的经历对你能有一些帮助&#xff0c;也希望你能喜欢我的作品。我还为大家申请了专属优…

【C++】哈希——unordered系列容器哈希概念哈希冲突

文章目录 1. unordered系列的关联式容器1.1 引言1.2 unordered_map的使用说明1.3 unordered_set的使用说明1.4 unordered_set和unordered_map的应用1.5 性能比较 2. 哈希概念3. 哈希函数4. 哈希冲突5. 哈希冲突的解决——开散列和闭散列5.1 闭散列5.2 开散列 1. unordered系列的…