• SSM框架学习——MyBatis Plus


    her~~llo,我是你们的好朋友Lyle,是名梦想成为计算机大佬的男人!

    博客是为了记录自我的学习历程,加强记忆方便复习,如有不足之处还望多多包涵!非常欢迎大家的批评指正。

    今天开始学习MyBatis Plus。主要有以下内容。

    • MyBatisPlus简介
    • 标准数据层开发
    • DQL控制
    • DML控制
    • 快速开发

    我们开始吧。

    目录

    一、MyBatisPlus简介

    二、MyBatisPlus入门案例

    三、标准数据层开发

    标准数据层CRUD功能

    Lombok

    分页功能

    开启日志(application.yml中)

    四、DQL编程控制

    条件查询

    查询方式

    查询关系

    处理null值

    查询投影

    查询条件设定

    字段映射与表名映射

    五、DML编程控制

    id生成策略控制

    多记录操作

    逻辑删除

    逻辑删除案例

    乐观锁

    乐观锁案例

    六、代码生成器


    一、MyBatisPlus简介

    MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率。

    官网: 

    MyBatis-Plus (baomidou.com)https://baomidou.com/

    特性:

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

    二、MyBatisPlus入门案例

    ①创建新模块,选择Spring初始化,并配置模块相关基础信息

    ②选择当前模块需要使用的技术集(仅保留JDBC)

     ③手动添加MP起步依赖

    1. <dependency>
    2. <groupId>com.baomidougroupId>
    3. <artifactId>mybatis-plus-boot-starterartifactId>
    4. <version>3.5.2version>
    5. dependency>

    ④设置jdbc参数(application.yml)

    1. spring:
    2. datasource:
    3. driver-class-name: com.mysql.cj.jdbc.Driver
    4. url: jdbc:mysql://localhost:3306/brand?useSSL=false
    5. username: root
    6. password: 123456
    7. type: com.alibaba.druid.pool.DruidDataSource

    ⑤制作实体类与表结构(类名与表名对应,属性名与字段名对应)

    ⑥定义数据接口,继承BaseMapper

    1. @Mapper
    2. public interface BookDao extends BaseMapper {
    3. }

    ⑦测试类中注入dao接口,测试功能

    1. @SpringBootTest
    2. class MybatisPlus01QuickstartApplicationTests {
    3. @Autowired
    4. private BookDao bookDao;
    5. @Test
    6. void testGetAll() {
    7. List<Book> books = bookDao.selectList(null);
    8. books.forEach(System.out::println);
    9. }
    10. }

    注意事项:

    • 由于MP并未被收录到idea的系统内置配置,无法直接选择加入
    • 如果使用Druid数据源,需要导入对应坐标

    三、标准数据层开发

    标准数据层CRUD功能

    1. @Test
    2. void testSelectById(){
    3. System.out.println(bookDao.selectById(1));
    4. }
    5. @Test
    6. void testSave(){
    7. Book book = new Book();
    8. book.setName("从你的全世界路过");
    9. book.setPrice(100.00);
    10. book.setType("言情");
    11. bookDao.insert(book);
    12. }
    13. @Test
    14. void testDelete(){
    15. List integerList = new ArrayList();
    16. integerList.add(12);
    17. integerList.add(13);
    18. bookDao.deleteBatchIds(integerList);
    19. }
    20. @Test
    21. void testUpdate(){
    22. Book book = new Book();
    23. book.setId(9);
    24. book.setPrice(50.00);
    25. bookDao.updateById(book);
    26. }

    Lombok

    Lombok,一个Java类库,提供了一组注解,简化POJ0实体类开发。

    1. <dependency>
    2. <groupId>org.projectlombokgroupId>
    3. <artifactId>lombokartifactId>
    4. <version>1.18.24version>
    5. <scope>providedscope>
    6. dependency>
    1. @Data //功能包含下面的注解
    2. //@Setter
    3. //@Getter
    4. //@ToString
    5. //@NoArgsConstructor
    6. //@AllArgsConstructor
    7. //@EqualsAndHashCode
    8. public class Book {
    9. private String name;
    10. private Double price;
    11. private Integer id;
    12. private String type;
    13. }

    常用注解:@Data
    为当前实体类在编译期设置对应的get/set方法,无参/有参构造方法,toString方法,hashCode方法,equals方法等。

    分页功能

    ①设置分页拦截器作为Spring管理的bean

    1. @Configuration
    2. public class MpConfig {
    3. @Bean
    4. public MybatisPlusInterceptor mybatisPlusInterceptor(){
    5. //定义MP拦截器
    6. MybatisPlusInterceptor mybatisPlusInterceptor =new MybatisPlusInterceptor();
    7. //添加具体的拦截器
    8. mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
    9. return mybatisPlusInterceptor;
    10. }
    11. }

    ②执行分页查询

    1. @Test
    2. void testGetByPage(){
    3. IPage page = new Page(1,5);
    4. bookDao.selectPage(page,null);
    5. System.out.println("当前页码值:"+page.getCurrent());
    6. System.out.println("每页显示书:"+page.getSize());
    7. System.out.println("一共多少页:"+page.getPages());
    8. System.out.println("一共多少条数据:"+page.getTotal());
    9. System.out.println("当前页数据:"+page.getRecords());
    10. }

    开启日志(application.yml中)

    1. #开启MP的日志输出
    2. mybatis-plus:
    3. configuration:
    4. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    四、DQL编程控制

    条件查询

    MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合

    查询方式

    查询格式一:常规格式

    1. QueryWrapper queryWrapper=new QueryWrapper();
    2. queryWrapper.lt("price",60);
    3. queryWrapper.gt("price",20);
    4. List books = bookDao.selectList(queryWrapper);
    5. books.forEach(System.out::println);

    查询格式二:lambda格式

    1. QueryWrapper queryWrapper=new QueryWrapper();
    2. queryWrapper.lambda().lt(Book::getPrice,50);
    3. List books1 = bookDao.selectList(queryWrapper);
    4. books1.forEach(System.out::println);

    查询格式三:lambda格式

    1. LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    2. //价格大于20小于50
    3. lambdaQueryWrapper.gt(Book::getPrice,20);
    4. lambdaQueryWrapper.lt(Book::getPrice,50);
    5. //价格小于40或者大于50
    6. lambdaQueryWrapper.gt(Book::getPrice,50).or().lt(Book::getPrice,40);
    7. List books2 = bookDao.selectList(lambdaQueryWrapper);
    8. books2.forEach(System.out::println);

    都支持链式编程。

    1. QueryWrapper queryWrapper=new QueryWrapper();
    2. queryWrapper.lt("price",60).gt("price",20);
    3. List books = bookDao.selectList(queryWrapper);
    4. books.forEach(System.out::println);

    查询关系

    并且(and)连着写就可以。

    或者(or)在中间加个or()。

    1. lambdaQueryWrapper.gt(Book::getPrice,50);
    2. lambdaQueryWrapper.or();
    3. lambdaQueryWrapper.lt(Book::getPrice,40);

    处理null值

    if条件控制(不推荐),就是在当前代码行前加if语句。

    推荐使用:条件参数控制(条件为true,连接当前条件,否则不连接)。

    lambdaQueryWrapper.gt(null!=book.getPrice(),Book::getPrice,20);

    查询投影

    查询结果包含模型类中部分属性

    1. //查询投影(lambda格式)
    2. LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    3. lambdaQueryWrapper.select(Book::getPrice,Book::getId);
    4. List books1 = bookDao.selectList(lambdaQueryWrapper);
    5. books1.forEach(System.out::println);

    查询结果包含模型类中未定义的属性(比如查询总共多少条数据)

    1. QueryWrapper queryWrapper = new QueryWrapper();
    2. queryWrapper.select("count(*) as count,type");
    3. queryWrapper.groupBy("type");
    4. List> maps = bookDao.selectMaps(queryWrapper);
    5. maps.forEach(System.out::println);

    查询条件设定

    等号匹配eq

    1. LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    2. lambdaQueryWrapper.eq(Book::getName,"我是神").eq(Book::getType,"玄幻");
    3. Book book = bookDao.selectOne(lambdaQueryWrapper);
    4. System.out.println(book);

    范围查询 lt le gt ge eq between
           

    1. //范围查询 lt le gt ge eq between
    2. LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    3. lambdaQueryWrapper.between(Book::getPrice,40,60);
    4. List bookList = bookDao.selectList(lambdaQueryWrapper);
    5. bookList.forEach(System.out::println);

    模糊匹配

    1. //模糊匹配
    2. LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper();
    3. lambdaQueryWrapper.like(Book::getName,"我");
    4. lambdaQueryWrapper.likeLeft(Book::getName,"我");
    5. lambdaQueryWrapper.likeRight(Book::getName,"我");
    6. List bookList = bookDao.selectList(lambdaQueryWrapper);
    7. bookList.forEach(System.out::println);

    分组查询聚合函数

    1. QueryWrapper queryWrapper = new QueryWrapper();
    2. queryWrapper.select("count(*) as count,type");
    3. queryWrapper.groupBy("type");
    4. List> maps = bookDao.selectMaps(queryWrapper);
    5. maps.forEach(System.out::println);

    其他条件查询可以自行搜索学习。

    字段映射与表名映射

    问题一:表字段与编码属性设计不同步

    问题二:编码中添加了数据库中未定义的属性

    问题三:采用默认查询开放了更多的字段查看权限

    问题四:表名与编码开发设计不同步

    名称:@TableField

    类型:属性注解
    位置:模型类属性定义上方
    作用:设置当前属性对应的数据库表中的字段关系
    相关属性:

    • value (默认):设置数据库表字段名称
    • exist:设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用
    • select:设置属性是否参与查询,此属性与select()映射配置不冲突

     
    名称:@TableName
    类型:类注解
    位置:模型类定义上方
    作用:设置当前类对应与数据库表关系
    相关属性

    • value:设置数据库表名称

    五、DML编程控制

    id生成策略控制

    1. public class Book {
    2. @TableId(type = IdType.AUTO)
    3. private Integer id;
    4. }

    名称:@TableId

    类型:属性注解
    位置:模型类中用于表示主键的属性定义上方

    作用:设置当前类中主键属性的生成策略
    相关属性

    • value:设置数据库主键名称
    • type:设置主键属性的生成策略,值参照IdType枚举值

    IdType枚举值:

    • AUTO(0)︰使用数据库id自增策略控制id生成
    • NONE(1)︰不设置id生成策略
    • INPUT(2):用户手工输入id
    • ASSIGN_ID(3)︰雪花算法生成id(可兼容数值型与字符串型)
    • ASSIGN_UUID(4):以UUID生成算法作为id生成策略

    对雪花算法以及UUID生成算法感兴趣的小伙伴请自行查看学习。

    还可以在application.yml中进行id生成策略以及表名前缀的全局设定(好用):

    1. mybatis-plus:
    2. global-config:
    3. db-config:
    4. #id生成策略
    5. id-type: auto
    6. #表名前缀
    7. table-prefix: tb_

    多记录操作

    按照主键删除多条记录

    1. List integerList = new ArrayList();
    2. integerList.add(1);
    3. integerList.add(2);
    4. bookDao.deleteBatchIds(integerList);

    根据主键查询多条记录

    1. List integerList = new ArrayList();
    2. integerList.add(1);
    3. integerList.add(2);
    4. bookDao.selectBatchIds(integerList);

    逻辑删除

    删除操作业务问题:删除某些记录时,相关的业务数据从数据库中丢弃,而不应该被丢弃。

    逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中

    逻辑删除案例

    ①数据库表中添加逻辑删除标记字段

    (可选)②实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

    1. public class Book {
    2. @TableLogic(value = "0",delval = "1")
    3. private Integer deleted;
    4. }

    (可选,推荐)③配置逻辑删除字段值

    1. mybatis-plus:
    2. global-config:
    3. db-config:
    4. logic-delete-field: deleted
    5. logic-not-delete-value: 0
    6. logic-delete-value: 1

    底层实现其实还是update。

    乐观锁

    业务并发现象带来的问题:秒杀

    乐观锁案例

    ①数据库表中添加锁标记字段

     

    ②实体类中添加对应字段,并设定当前字段为逻辑删除标记字段

    1. public class Book {
    2. @Version
    3. private Integer version;
    4. }

    ③配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装

    1. @Configuration
    2. public class MpConfig {
    3. @Bean
    4. public MybatisPlusInterceptor mybatisPlusInterceptor(){
    5. //定义MP拦截器
    6. MybatisPlusInterceptor mybatisPlusInterceptor =new MybatisPlusInterceptor();
    7. //添加乐观锁拦截器
    8. mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    9. return mybatisPlusInterceptor;
    10. }
    11. }

    ④使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行

    1. @Test
    2. void testUpdate(){
    3. Book book1 = bookDao.selectById(5);
    4. Book book2 = bookDao.selectById(5);
    5. book2.setName("NININIaaa");
    6. bookDao.updateById(book2);
    7. book1.setName("NININIbbb");
    8. bookDao.updateById(book1);
    9. }

    六、代码生成器

    模板:MyBatisPlus提供
    数据库相关配置:读取数据库获取信息

    开发者自定义配置: 手工配置

    ①导入坐标

    1. <dependency>
    2. <groupId>com.baomidougroupId>
    3. <artifactId>mybatis-plus-generatorartifactId>
    4. <version>3.4.0version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.apache.velocitygroupId>
    8. <artifactId>velocity-engine-coreartifactId>
    9. <version>2.3version>
    10. dependency>

    ②//创建代码生成器对象,进行配置,执行生成代码操作

    1. public class Generator {
    2. public static void main(String[] args) {
    3. //为AutoGenerator添加dataSource,读取数据库
    4. AutoGenerator autoGenerator = new AutoGenerator();
    5. DataSourceConfig dataSource = new DataSourceConfig();
    6. dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
    7. dataSource.setUrl("jdbc:mysql://localhost:3306/brand?serverTimezone=UTC");
    8. dataSource.setUsername("root");
    9. dataSource.setPassword("123456");
    10. autoGenerator.setDataSource(dataSource);
    11. //设置全局配置
    12. GlobalConfig globalConfig = new GlobalConfig();
    13. globalConfig.setOutputDir(System.getProperty("user.dir")+"/MybatisPlus_01_quickstart/src/main/java");//设置生成代码的目录
    14. globalConfig.setOpen(true); //设置生成完毕是否打开生成代码所在目录
    15. globalConfig.setAuthor("ylm");//设置作者名
    16. globalConfig.setFileOverride(true);//设置是否覆盖原始生成的文件
    17. globalConfig.setMapperName("%sDao");//设置数据层接口名,%s为占位符,指模块名称
    18. globalConfig.setIdType(IdType.ASSIGN_ID);
    19. autoGenerator.setGlobalConfig(globalConfig);
    20. //设置包名相关配置
    21. PackageConfig packageConfig =new PackageConfig();
    22. packageConfig.setParent("com.aaa");//设置父类包名
    23. packageConfig.setEntity("domain");//设置实体类包名
    24. packageConfig.setMapper("dao");//设置数据层包名
    25. autoGenerator.setPackageInfo(packageConfig);
    26. //策略设置
    27. StrategyConfig strategyConfig = new StrategyConfig();
    28. strategyConfig.setInclude("tb_book");//设置哪些表生成
    29. strategyConfig.setTablePrefix("tb_");//告诉它前缀是什么,生成实体类就不带前缀了
    30. strategyConfig.setRestControllerStyle(true);//是否启用REST风格
    31. strategyConfig.setVersionFieldName("version");//设置乐观锁字段
    32. strategyConfig.setLogicDeleteFieldName("deleted");//设置逻辑删除字段
    33. strategyConfig.setEntityLombokModel(true);//设置是否启用lombok
    34. autoGenerator.setStrategy(strategyConfig);
    35. //执行代码生成操作
    36. autoGenerator.execute();
    37. }
    38. }

    补充,MP还提供了IService来简化业务层的开发,同数据层类似,但是一半不用,因为业务层需要添加别的代码。有应用可以用。

    结语:

    SSM框架学习大致就到此结束了,复习复习就开始下一阶段咯。冲!

  • 相关阅读:
    详解CAN总线:高速CAN总线和低速CAN总线的特性
    代码随想录 | Day 59 - LeetCode 503. 下一个更大元素II、LeetCode 42. 接雨水
    基于单片机的电子琴设计
    Azure 机器学习:MLOps - 使用 Azure 机器学习进行模型管理、部署和监视
    考华为HCIP证书多钱?
    基础算法练习200题11、鸡兔同笼
    LabVIEW样式检查表1
    职场Excel:求和家族,不简单
    比例-积分-微分 (PID) 鲁棒控制及电流反馈以确保 UPS 的稳定性(Matlab代码实现)
    mysql数据库中mysql database 数据被破坏产生的一系列问题
  • 原文地址:https://blog.csdn.net/weixin_58035422/article/details/126050642