Mybatis Plus | 快速入门

太过爱你忘了你带给我的痛 2024-04-22 19:06 102阅读 0赞

在这里插入图片描述

?wei_shuo的个人主页

?wei_shuo的学习社区

?Hello World !


Mybatis Plus

在这里插入图片描述

MyBatis-Plus(简称 MP)是一个基于 MyBatis 的增强工具,它对 Mybatis 的基础功能进行了增强,但未做任何改变。使得我们可以可以在 Mybatis 开发的项目上直接进行升级为 Mybatis-plus,正如它对自己的定位,它能够帮助我们进一步简化开发过程,提高开发效率;

特性

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

环境准备

  • 数据库准备

    DROP TABLE IF EXISTS user;

    CREATE TABLE user
    (

    1. id BIGINT(20) NOT NULL COMMENT '主键ID',
    2. name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    3. age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    4. email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    5. 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’);

  • 创建springboot-mybatis-plus依赖导入




    com.baomidou
    mybatis-plus-boot-starter
    3.0.5



    mysql
    mysql-connector-java



    org.projectlombok
    lombok



    org.springframework.boot
    spring-boot-starter-web

  • 数据源、日志配置application.properties

    数据库连接配置

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

    配置日志

    mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

初步使用

  • pojo/User.java类配置

    package com.wei.pojo;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {

  1. private Long id;
  2. private String name;
  3. private Integer age;
  4. private String email;
  5. }
  • mapper/UserMapper.java配置;继承mybatis-plus接口BaseMapper

    package com.wei.mapper;

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.wei.pojo.User;
    import org.springframework.stereotype.Repository;

    @Repository
    public interface UserMapper extends BaseMapper {

  1. }
  • application中配置注释扫描mapper路径

    //扫描mapper文件夹
    @MapperScan(“com.wei.mapper”)

  • test测试

    package com.wei;

    import com.wei.mapper.UserMapper;
    import com.wei.pojo.User;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;

    import java.util.List;

    @SpringBootTest
    class SpringbootMybatisPlusApplicationTests {

  1. @Autowired
  2. private UserMapper userMapper;
  3. @Test
  4. void contextLoads() {
  5. //查询全部用户
  6. List<User> users = userMapper.selectList(null);
  7. users.forEach(System.out::println);
  8. }
  9. }

主键生成策略

主键生成策略:UUID、自增ID、雪花算法、Redis、zookeeper解释他们的区别和作用

  • UUID(Universally Unique Identifier):UUID是一种算法,用于生成全局唯一的标识符。UUID是由一组随机数字和字母组成,长度为36个字符,通常以连字符分隔。UUID的优点是非常安全,几乎不可能重复,但是它的缺点是生成的标识符比较长,不太适合作为数据库主键
  • 自增ID:自增ID是指在数据库中自动递增的整数,通常作为表的主键。自增ID的优点是简单易用,易于维护和管理,但是它的缺点是在分布式系统中可能会产生冲突,因为每个节点的自增ID都是独立的
  • 雪花算法(Snowflake):雪花算法是Twitter开源的分布式ID生成算法。它使用一个64位的整数来表示唯一标识符,其中包括一个时间戳和一些节点信息。雪花算法的优点是生成的标识符比较短,可以在分布式系统中安全使用,但是它的缺点是需要维护节点信息,同时需要考虑时间戳的溢出问题
  • Redis:Redis是一种基于内存的键值对存储系统。它可以用作分布式系统中的数据存储和缓存。在Redis中,可以使用自增命令INCR来生成唯一标识符。Redis的优点是非常快速和可靠,但是它的缺点是需要额外的系统维护和管理
  • Zookeeper:Zookeeper是一个分布式的开源协调系统。它可以用于分布式系统中的数据存储和协调。在Zookeeper中,可以使用序列节点来生成唯一标识符。Zookeeper的优点是可以实现分布式系统中的数据同步和协调,但是它的缺点是需要额外的系统维护和管理

总的来说,不同的主键生成策略适用于不同的场景。如果需要生成全局唯一的标识符,可以使用UUID。如果需要简单易用的主键,可以使用自增ID。如果需要在分布式系统中生成唯一标识符,可以使用雪花算法、Redis或Zookeeper

  • 默认方案,全局唯一ID

    //默认方案,全局唯一ID

    1. @TableId(type = IdType.ID_WORKER)
  • 主键自增

    public enum IdType {

    1. AUTO(0), //数据库id自增
    2. NONE(1), //未设置主键
    3. INPUT(2), //手动输入
    4. ID_WORKER(3), //默认全局id
    5. UUID(4), //全局唯一id uuid
    6. ID_WORKER_STR(5); //ID_WORKER字符串表示

    }

  • 对应id字段添加主键生成策略

    package com.wei.pojo;

    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableId;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {

    1. @TableId(type = IdType.INPUT)
    2. private Long id;
    3. private String name;
    4. private Integer age;
    5. private String email;

    }

CURD

查询

  1. @Test
  2. void contextLoads() {
  3. //查询全部用户
  4. List<User> users = userMapper.selectList(null);
  5. users.forEach(System.out::println);
  6. }

插入

  1. @Test
  2. public void testInsert(){
  3. User user = new User();
  4. user.setName("wei_shuo");
  5. user.setAge(18);
  6. user.setEmail("11096075493@qq.com");
  7. int insert = userMapper.insert(user);
  8. System.out.println(insert);
  9. System.out.println(user);
  10. }

更新

  1. @Test
  2. public void testUpdate(){
  3. User user = new User();
  4. //通过条件自动拼接动态sql
  5. user.setId(6L);
  6. user.setAge(10);
  7. user.setName("wei");
  8. userMapper.updateById(user);
  9. }

查询

  1. //查询单个查询
  2. @Test
  3. public void TestSelectById() {
  4. User user = userMapper.selectById(1L);
  5. System.out.println("输出:" + user);
  6. }
  7. //查询多个查询
  8. @Test
  9. public void TestSelectByBatchIds(){
  10. List<User> list = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
  11. list.forEach(System.out::println);
  12. }
  13. //条件查询
  14. @Test
  15. public void TestSelectByBatchId(){
  16. HashMap<String, Object> map = new HashMap<>();
  17. //自定义查询
  18. map.put("name","Tom");
  19. List<User> list = userMapper.selectByMap(map);
  20. list.forEach(System.out::println);
  21. }

分页查询

  • limit分页
  • pageHelper插件
  • MP插件

  • 分页配置

    package com.wei.config;

    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.annotation.EnableTransactionManagement;

    @MapperScan(“con.wei.mapper”) //mapper文件夹扫描
    @EnableTransactionManagement //默认事务管理
    @Configuration //配置类注解
    public class MybatisPlusConfig {

  1. /**
  2. 自动分页: PaginationInnerInterceptor
  3. 多租户: TenantLineInnerInterceptor
  4. 动态表名: DynamicTableNameInnerInterceptor
  5. 乐观锁: OptimisticLockerInnerInterceptor
  6. sql 性能规范: IllegalSQLInnerInterceptor
  7. 防止全表更新与删除: BlockAttackInnerInterceptor
  8. **/
  9. @Bean
  10. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  11. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  12. //乐观锁配置
  13. interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  14. //分页配置
  15. interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
  16. return interceptor;
  17. }
  18. }
  • 测试

    //分页查询

    1. @Test
    2. public void TestPage(){
    3. Page<User> page = new Page<>(1,5);
    4. userMapper.selectPage(page,null);
    5. page.getRecords().forEach(System.out::println);
    6. System.out.println(page.getTotal());
    7. }

删除

  1. //删除
  2. @Test
  3. public void TestDeleteById(){
  4. userMapper.deleteById(1641610894939250691L);
  5. }
  6. //批量删除
  7. @Test
  8. public void TestDeleteBatchIds(){
  9. userMapper.deleteBatchIds(Arrays.asList(1641610894939250690L,1641027507828424706L));
  10. }
  11. //条件删除
  12. @Test
  13. public void TestDeleteMap(){
  14. HashMap<String, Object> map = new HashMap<>();
  15. map.put("name","THY222");
  16. userMapper.deleteByMap(map);
  17. }

逻辑删除

  • 物理删除:数据库中直接移除
  • 逻辑删除:数据库中没有直接移除,使用变量使其失效

  • 数据库增加字段deleted默认值为0

  • 实体类增添字段

    @TableLogic //逻辑删除
    private Integer deleted;

  • application.properties配置逻辑删除

    配置逻辑删除

    mybatis-plus.global-config.db-config.logic-delete-value=1
    mybatis-plus.global-config.db-config.logic-not-delete-value=0

  • 执行删除

    //逻辑删除

    1. @Test
    2. public void TestDeleteLogicById(){
    3. userMapper.deleteById(6L);
    4. }
  • 查看数据库:数据库中没有直接移除,使用变量使其失效

在这里插入图片描述

自动填充

数据库级别

  • 数据表中新增字段create_time、update_time

代码级别

  • 实体类字段添加注解

    //字段填充内容

    1. @TableField(fill = FieldFill.INSERT)
    2. private Date createTime;
    3. @TableField(fill = FieldFill.INSERT_UPDATE)
    4. private Date updateTime;
  • 编写处理器MyMetaObjectHandler.java

    package com.wei.handler;

    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;

    import java.util.Date;

  1. @Slf4j
  2. @Component
  3. public class MyMetaObjectHandler implements MetaObjectHandler {
  4. //插入时的填充策略
  5. @Override
  6. public void insertFill(MetaObject metaObject) {
  7. log.info("start insert fill ....");
  8. //设置字段的值 setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
  9. this.setFieldValByName("createTime",new Date(),metaObject);
  10. this.setFieldValByName("updateTime",new Date(),metaObject);
  11. }
  12. //更新时的填充策略
  13. @Override
  14. public void updateFill(MetaObject metaObject) {
  15. log.info("start insert fill ....");
  16. this.setFieldValByName("updateTime",new Date(),metaObject);
  17. }
  18. }

乐观锁 | 悲观锁

乐观锁假设多个线程之间不会产生冲突,因此在读取数据时不加锁,而只有在更新数据时才加锁。在更新数据时,先检查当前状态是否与预期一致,如果一致则进行更新,否则认为数据已被其他线程修改,需要回滚或重试

悲观锁则相反,它假设多个线程之间会产生冲突,因此在读取数据时就会加锁,防止其他线程同时修改数据。在更新数据时,悲观锁也会继续保持锁定状态,直到操作完成后才释放锁

总体来说,乐观锁更适合读多写少的场景,悲观锁则更适合写多读少的场景。但具体使用哪种锁机制还需要根据具体情况进行选择

乐观锁实现方式:

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败

  • 实体类注解

    @Version //乐观锁注解

    1. private Integer version;
  • 注册组件:mybatis-plus 版本:3.5.3

    package com.wei.config;

    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.annotation.EnableTransactionManagement;

    @MapperScan(“con.wei.mapper”) //mapper文件夹扫描
    @EnableTransactionManagement //默认事务管理
    @Configuration //配置类注解
    public class MybatisPlusConfig {

  1. /**
  2. 自动分页: PaginationInnerInterceptor
  3. 多租户: TenantLineInnerInterceptor
  4. 动态表名: DynamicTableNameInnerInterceptor
  5. 乐观锁: OptimisticLockerInnerInterceptor
  6. sql 性能规范: IllegalSQLInnerInterceptor
  7. 防止全表更新与删除: BlockAttackInnerInterceptor
  8. **/
  9. @Bean
  10. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  11. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  12. //乐观锁配置
  13. interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
  14. //分页配置
  15. interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
  16. return interceptor;
  17. }
  18. }
  • 测试

    //乐观锁测试成功

    1. @Test
    2. public void TestOptimisticLockerInterceptor() {
    3. //查询用户信息
    4. User user = userMapper.selectById(1L);
    5. //修改用户信息
    6. user.setName("THY");
    7. user.setEmail("123456789@qq.com");
    8. //执行更新操作
    9. userMapper.updateById(user);
    10. }
    11. //乐观锁测试失败
    12. @Test
    13. public void FailOptimisticLockerInterceptor() {
    14. //线程一
    15. User user = userMapper.selectById(1L);
    16. user.setName("THY");
    17. user.setEmail("123456789@qq.com");
    18. //线程二,插队更新user2
    19. User user2 = userMapper.selectById(1L);
    20. user2.setName("THY222");
    21. user2.setEmail("123456789@qq.com");
    22. userMapper.updateById(user2);
    23. //自旋锁多次尝试提交
    24. userMapper.updateById(user); //如果没有乐观锁就会覆盖插队线程的值
    25. }

性能分析插件

  • 依赖导入

    1. <dependency>
    2. <groupId>p6spy</groupId>
    3. <artifactId>p6spy</artifactId>
    4. <version>3.9.1</version>
    5. </dependency>
  • spy.properties配置

    3.2.1以上使用

    modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory

    3.2.1以下使用或者不配置

    modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory

    自定义日志打印

    logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger

    日志输出到控制台

    appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger

    使用日志系统记录 sql

    appender=com.p6spy.engine.spy.appender.Slf4JLogger

    设置 p6spy driver 代理

    deregisterdrivers=true

    取消JDBC URL前缀

    useprefix=true

    配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.

    excludecategories=info,debug,result,commit,resultset

    日期格式

    dateformat=yyyy-MM-dd HH:mm:ss

    实际驱动可多个

    driverlist=org.h2.Driver

    是否开启慢SQL记录

    outagedetection=true

    慢SQL记录标准 2 秒

    outagedetectioninterval=2

  • application.properties配置

    设置开发环境

    spring.profiles.active=dev

    配置p6spy数据库连接

    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver

  • 效果展示

在这里插入图片描述

开发环境、测试环境、生产环境的作用和区别

开发环境、测试环境、生产环境之间的主要区别在于它们所涉及的目标和需求不同;开发环境注重于代码编写和调试,测试环境注重于软件质量和功能测试,而生产环境则注重于可靠性和性能优化。同时,这些环境中的设置和配置也可以不同,以满足其不同的目的

  • 开发环境是用于软件开发和调试的环境,它通常包括代码编辑器、编译器、调试器以及其他必要的工具
  • 测试环境是用于软件测试的环境,其中包含了模拟生产环境的硬件、软件和网络设置,可以对软件进行各种测试,以确保其质量和稳定性。
  • 生产环境是用于部署和运行实际应用程序的环境。它是最终用户使用软件的环境,因此需要具有高可用性、可扩展性、安全性和性能等特征

代码生成器

  • 依赖导入


    com.baomidou
    mybatis-plus-generator
    最新版本
  • 快速生成

    FastAutoGenerator.create(“url”, “username”, “password”)

    1. .globalConfig(builder -> {
    2. builder.author("baomidou") // 设置作者
    3. .enableSwagger() // 开启 swagger 模式
    4. .fileOverride() // 覆盖已生成文件
    5. .outputDir("D://"); // 指定输出目录
    6. })
    7. .packageConfig(builder -> {
    8. builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
    9. .moduleName("system") // 设置父包模块名
    10. .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
    11. })
    12. .strategyConfig(builder -> {
    13. builder.addInclude("t_simple") // 设置需要生成的表名
    14. .addTablePrefix("t_", "c_"); // 设置过滤表前缀
    15. })
    16. .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
    17. .execute();
  • 交互式生成

    FastAutoGenerator.create(DATA_SOURCE_CONFIG)

    1. // 全局配置
    2. .globalConfig((scanner, builder) -> builder.author(scanner.apply("请输入作者名称?")).fileOverride())
    3. // 包配置
    4. .packageConfig((scanner, builder) -> builder.parent(scanner.apply("请输入包名?")))
    5. // 策略配置
    6. .strategyConfig((scanner, builder) -> builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
    7. .controllerBuilder().enableRestStyle().enableHyphenStyle()
    8. .entityBuilder().enableLombok().addTableFills(
    9. new Column("create_time", FieldFill.INSERT)
    10. ).build())
    11. /*
    12. 模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
    13. .templateEngine(new BeetlTemplateEngine())
    14. .templateEngine(new FreemarkerTemplateEngine())
    15. */
    16. .execute();
  1. // 处理 all 情况
  2. protected static List<String> getTables(String tables) {
  3. return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
  4. }

? 结语:创作不易,如果觉得博主的文章赏心悦目,还请——点赞?收藏⭐️评论?


在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,102人围观)

还没有评论,来说两句吧...

相关阅读