朝阳博客

  • Article
  • Project
  • HTML+CSS
  • Bootstrap
  • JavaScript
  • jQuery
  • PHP
  • Java
  • Linux
  • MySQL
朝阳博客
一款专注于博客的响应式网站
  1. 首页
  2. Java
  3. 正文

MyBatis-Plus笔记[按照狂神说Java整理的]

2021年10月28日 2993点热度 6人点赞 0条评论

MyBatis-Plus

导包

<!--数据库驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lomok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>

不要同时导入Mybatis和Mybatis-plus的jar包,会存在版本差异

连接数据库

  • mysql 5 驱动不同 com.mysql.jdbc.Driver
  • mysql 8 驱动不同 com.mysql.cj.jdbc.Driver 需要增加时区而配置
  • 高级驱动兼容低驱动,用cj就行
    spring.datasource.user=root
    spring.datasource.password=123456
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

使用

  • 在对应的mapper上继承基本的类BaseMapper
    @Repository //代表持久层
    public interface UserMapper extends BaseMapper<User>{}

    所有的CRUD操作都已经便携而完成了

  • 在文件的初始方法xxxApplication里面添加注解
    • 扫描mapper文件夹
    • @MapperScan("com.yang.mapper")
  • 继承了BaseMapper,所有方法都来自于父类,也可以自己编写
    • UserMapper目前就不用自己写东西了
  • 执行语句
    • 查询全部用户
      • userMapper.selectList(null);
        • 参数是一个Wrapper,条件构造器,这里我们先不写,写null就可以了
        • user.forEach(System.out::println);就可以直接输出了

配置日志

  • 可以查看sql执行时的东西
    mybatis-plus.configuration.log-impl=org.apache.ibatis.loggin.stdout.StdOutImpl
    mybatis-plus:
    configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

CRUD扩展

查询全部用户

@Test
void contextLoads(){
    //参数是一个Wrapper,条件构造器,这里我们先不用写,写上null就可以了
    //查询全部用户
    List<Uuser> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}

插入

@Test
public void testInsert(){
    User user = new User();
    user.setName("名字");
    user.setAge(18);
    user.setEmail("123456789@qq.com");
    int result = userMapper.insert(user);//帮我们自动生成id
    System.out.println(result);//受影响的行数
    System.out.println(user);//发现id会自动回填
}

雪花算法

  • 主键生成策略
  • 分布式系统唯一id生成
  • 链接:https://www.cnblogs.com/haoxinyue/p/5208136.html
  • snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。雪花算法支持的TPS可以达到419万左右(2^22*1000)。
  • 对应数据库中的主键(uuid、自增id、雪花算法、redis、zookeeper!)
  • 想自增id在pojo方在id上面添加个@TableId(type=IdType.Auto)
  • 类型@TableId(type=IdType.xxxx)
    public enum IdType{
    AUTO(0), //数据库id自增
    NONE(1), //未设置主键
    INPUT(2), //手动输入
    ID_WORKER(3), //默认的全局唯一id
    UUID(4), //全局唯一id uuid
    ID_WORKER_STR(5); //ID——WORKER 字符串表示法
    }

更新

@Test
public void testUpdate(){
     User user = new User();
    //通过条件自动拼接动态SQL
    user.setId(6L);
    user.setName("aaa");
    //注意:updateById但是参数是一个对象
    int i = userMapper.updateById(user);
    System.out.println(i);
}

自动填充

  • 创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新!
  • 阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!
  • 在数据库新增个列叫createTime和updateTime类型为datetime默认CURRENT_TIMESTAMP, updateTime选上更新

方式一:数据库级别(工作中不允许你修改数据库)

private Date createTime;
private Date updateTime;

方式二:代码级别

  • 在数据库新增个列叫createTime和updateTime类型为datetime,和方法一完全不一样
    //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
  • 创建个handler里面创建方法MyMetaObjectHandler implements MetaObjectHandler来个注解@Component丢给Spring需要日志的话需要添加@Slf4j

锁

  • 乐观锁:十分乐观,它总认为不会出现问题,无论干什么都不去上锁,如果出现问题,再次更新值测试
    • version
    • new version
  • 悲观锁:十分悲观,它总认为宗师出现问题,无论干什么都会上锁!再去操作
乐观锁实现方式
  • 取出记录时,获得当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
乐观锁:1.先查询,获得版本号version = 1--A
update user set name = "kuangshen",version = version + 1
where id = 2 and version = 1
--B 线程抢先完成,这个时候version = 2,会导致A修改失败
update user set name = "kuangshen",version = version + 1
where id = 2 and version = 1
测试MP乐观锁插件
  1. 给数据库中增加version字段 默认是值是1
  2. 在pojo类的version加一个@Version注解,乐观锁注解
  3. 注册组件
    @MapperScan("com.yang.mapper") //扫描我们的mapper文件夹,在主方法内就不用写这个了
    @EnableTransactionManagement //事务注解
    @Configyration //配置类
    public class MyBatisPlusConfig{
    //注册乐观锁插件
    @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
    }
  4. 测试
    //测试乐观锁成功!单线程下
    public void testOptimisticLocker1(){
    //1.查询用户信息
    User user = userMapper.slectById(1L);
    //2.修改用户信息
    user.setName("kuangshen");
    user.setEmail("24736743@qq.com");
    //3.执行更新操作
    userMapper.updateById(user);
    }
    //测试乐观锁失败!多线程下
    public void testOptimisticLocker2(){
    //1.查询用户信息
    User user = userMapper.slectById(1L);
    //2.修改用户信息
    user.setName("kuangshen");
    user.setEmail("24736743@qq.com");
    //模拟另外一个多线程执行了插队操作
    //2.修改用户信息
    User user = userMapper.slectById(1L);
    user2.setName("kuangshen222");
    user2.setEmail("24736743@qq.com");
    //3.执行更新操作
    userMapper.updateById(user2);
    //自旋锁来多次尝试提交!
    userMapper.updateById(user); //如果没有乐观锁就会覆盖插队线程的值
    }

查询操作

//查询
public void testSelectById(){
    User user = userMapper.selectById(1L);
    System.out.println(user);
}
//批量查询
public void testSelectByBatchId(){
    List<User> users = userMapper.selectBathIds(Arrays.asList(1,2,3));
    users.forEach(System.out::println);
}
//条件查询 map
public void testSelectByBathIds(){
    HashMap<String,Object> map = new HashMap<>();
    //自定义要查询
    map.put("name","狂神说Java");
    map.put("age",3);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

分页查询

分页在网站使用的十分之多!

  1. 原石的limit进行分页
  2. pageHelper第三方插件
  3. MP其实也内置了分页插件
操作
  1. 配置拦截器,放入MyBatisPlusConfig文件就行
    //Spring boot方式
    @Configuration
    @MapperScan("com.baomidou.cloud.service.*.mapper*")
    public class MybatisPlusConfig {
    // 旧版
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
    
    //或者第一步直接
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
    }
  2. 直接使用Page对象即可
  3. 测试分页查询
    public void testPage(){
    //参数一:当前页
    //参数二:页面大小
    //使用了分页插件之后,所有的分页操作 也变得简单了
    Page<User> page = nwe Page<>(1,5);
    userMapper.selectPage(page,null);
    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());//查看总数页
    }

删除

  1. 根据id删除记录
    //id删除
    public void testDeleteById(){
    userMapper.deleteById(1L);
    }
    //id批量删除
    public void testDeleteBatchId(){
    userMapper.deleteBatchIds(Array.asList(1L,2L));
    }
    //通过map删除
    public void testDeleteBatchId(){
    HashMap<String,Object> map = new HashMap<>();
    map.put("name","狂神说Java");
    userMapper.deleteByMap(map);
    }

    我们在工作中会遇到一些问题:逻辑删除!

逻辑删除

  1. 物理删除:从数据库中直接移除
  2. 逻辑删除:再数据库中没有被移除,而是通过一个变量来让他失效!deleted = 0 = deleted = 1

管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!

测试:

  1. 在数据表中增加一个deleted字段值等于0
  2. pojo中增加属性,增加注解@TableLogic
  3. 新版3.1.1不用写@Bean
    mybatis-plus:
    global-config:
    db-config:
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
  4. 测试:
    //id删除
    public void testDeleteById(){
    userMapper.deleteById(1L);
    }
    //id批量删除
    public void testDeleteBatchId(){
    userMapper.deleteBatchIds(Array.asList(1L,2L));
    }
    //通过map删除
    public void testDeleteBatchId(){
    HashMap<String,Object> map = new HashMap<>();
    map.put("name","狂神说Java");
    userMapper.deleteByMap(map);
    }
  5. 走的并不是删除操作,做了更新操作,记录依旧在数据库deleted=1了,用了MP直接查就行了,不用判断,自动过滤逻辑删除的字段

以上的所有CRUD操作及其扩展操作,我们必须精通掌握!会大大提高你的工作和写项目的效率!

性能分析插件

我们在平时的开发中,会遇到一些慢sql。测试!druid....
MP也提供心梗分析插件,如果超过这个时间就停止运行

  1. 导入插件
  2. 测试使用
  3. SQL执行效率插件【3.1.1以后不用】
    @Bean
    @Profile({"dev","test"}) //设置dev test环境开启,保证我们的效率
    public PerformanceInterceptor performanceInterceptor(){
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    //在工作中,不允许用户等待
    performanceInterceptor.setMaxTime(100);//ms毫秒 设置sql执行的最大时间,如果超过了则不执行,然后会报错
    performanceInterceptor.setFormat(true);//开启格式化代码
        return performanceInterceptor;
    }

    4.配置

    1. 设置开发环境
      spring.profiles.active=dev

      2.Maven

      <dependency>
      <groupId>p6spy</groupId>
      <artifactId>p6spy</artifactId>
      <version>最新版本</version>
      </dependency>

      3.yml

      spring:
      datasource:
      driver-class-name: com.p6spy.engine.spy.P6SpyDriver
      url: jdbc:p6spy:h2:mem:test
      ...

      4.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

条件构造器

十分重要:Wrapper

我们写一些复杂的sql就可以用它来代替

  1. 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
    void test1(){
    //查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
    QuerWrapper<User> wrapper = new QuerWrapper<>();
    wrapper
        .isNotNull("name")//不为空
        .isNotNull("email")//不为空
        .ge("age",12);//大于等于
    userMapper.selectList(wrapper).forEach(System.out::println);
    }
  2. 名字等于狂神说
    void test2(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","狂神说");
    User user = userMapper.selectOne(wrapper);//查询一个数据,出现多个结果使用List或Map
    System.out.println(user);
    }
  3. 查询年龄在20~30岁之间的用户
    void test3(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age",20,30);//区间
    Integer count = userMapper.selectCount(Wrapper);//查询结果数
    System.out.println(count);
    }
  4. 模糊查询,记住查看输出的SQL进行分析
    void test4(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //左和右 %e%
    wrapper.notLike("name","e").likeRight("email","t%");
    List<Map<String,Object>> maps = userMapper.selectMaps(Wrapper);//查询结果数
    maps.forEach(System.out::println);
    }
  5. 内链接 in查询
    void test5(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //id在子查询中查出来
    wrapper.inSql("id","select id from user where id < 3");
    List<Object> objects = userMapper.selectObjs(Wrapper);
    objects.forEach(System.out::println);
    }
  6. 排序
    void test6(){
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    //通过id进行排序
    wrapper.orderByDesc("id");//降序
    wrapper.orderByAsc("id");//升序
    List<User> users = userMapper.selectList(Wrapper);
    users.forEach(System.out::println);
    }

代码自动生成器

禁用thymeleaf缓存

spring.thymeleaf.cache=false
  1. AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
  2. 创建个测试类叫xxxCode
    //代码自动生成器
    public class KuangCode{
    public static void main(String[] args){
        //需要构建一个代码自动生成器 对象
        AutoGenerator mpg = new AutoGenerator();
        //配置策略
        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");//路径
        gc.setAuthor("狂神说");//作者
        gc.setOpen(false);//是否打开生成的文件夹
        gc.setFileOverride(false);//是否覆盖
        gc.setServiceName("%sService");//去service的I前缀
        gc.setIdType(IdType.ID_WORKER);//算法
        gc.setDateType(DateType.ONLY_DATE);//日期
        gc.setSwagger2(true);//Swagger文档
        mpg.setGlobalConfig(gc);
        //2.设置数据源
        DateSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DBType.MYSQL);
        mpg.setDataSource(dsc);
        //3.包的配置
        PackageInfo pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.kuang");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);
        //4.策略
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user","user","admin");//设置要映射的表名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);//自动生成Lombok
        strategy.setLogincDeleteFieldName("deleted");
        //自动填充配置
        TableFill gmtCreate = new TableFill("gmt_create",FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
        ArrayList<TableFills> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        //乐观锁
        strategy.setVersionFieldName("version");
        //驼峰命名
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);//localhost:8080/hello_id_2
        mpg.setStrategy(strategy);
        mpg.execute();//执行
    }
    }

完章

标签: 暂无
最后更新:2023年3月17日

aiyao

你要加油,你喜欢的人还没结婚。

点赞
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2021 zhaoyangweb.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

冀ICP备2021020018号-1