ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Mybatis进阶02-MybatisPlus

2021-09-05 13:01:18  阅读:141  来源: 互联网

标签:02 MybatisPlus name age wrapper 查询 Mybatis new id


Mybatis进阶02-MybatisPlus

1.修改数据

  1. 测试用例,SQL自动拼接不为null的字段。
@Test
void testUpdate() {
    User user = new User();
    user.setId(1011L);
    user.setName("");
    // 通过id更新,会自动填充更新不为null的列
    int result = userMapper.updateById(user);
    System.out.println(result);
}

2.修改数据-自动填充

  1. 阿里开发手册上说:数据库中的表需要有create_timeupdate_time字两个字段,有两种方式可以实现。

    1. 实现方式一:数据库层面。
    # 通过Navicat增加两个字段
    #创建列 create_time 类型datetime 默认值为 current_timestamp
    #创建列 update_time 类型datetime 默认值为 current_timestamp 并勾选 根据当前时间戳更新
    
    1. 实现方式二。使用MybatisPlus的MetaObjectHandler,自动补全create_timeupdate_time
  2. 实现方式二,数据库和Java实体类增加字段。

//`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
//`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',

// 插入时更新
@TableField(fill = FieldFill.INSERT)
private Date createTime;
// 插入和更新时更新数据
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
  1. 实现方式二,增加Handle进行SQL拦截。
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 插入数据时,设置create_time和update_time值,值为new Date()
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert data {}", metaObject);
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }

    /**
     * 更新时设置update_time的值
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

3.MybatisPlus实现乐观锁

  1. 数据库和Java类增加Version字段。
//`version` int(0) NULL DEFAULT 1 COMMENT '乐观锁',

@Version
private Integer version;
  1. 配置乐观锁的拦截器。
@MapperScans({
        @MapperScan("com.my.mybatisplus.demo01.dao")
})
@Configuration
public class MybatisPlusConfig {

    /**
     * 注入乐观锁组件。本质是通过拦截器进行SQL拼接。
     * update set version=oldVersion+1 where id=? and version=oldVersion
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 乐观锁
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

4.分页查询

  1. 配置分页查询的拦截器。
@MapperScans({
        @MapperScan("com.my.mybatisplus.demo01.dao")
})
@Configuration
public class MybatisPlusConfig {

    /**
     * 注入分页插件
     * @return
     */
    //@Bean
    public MybatisPlusInterceptor interceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
  1. 代码实现。执行分页查询前,会执行count(*)操作获取总记录数。
@Test
void testPage() {
    // 分页本质,通过拦截器在SQL执行前进行 LIMIT ? OFFSET ? 的拼接
    // MybatisPlus会将数据存放在Page中
    Page<User> page = new Page<>(2, 3);

    userMapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println);

    // 获得查询的数据
    page.getRecords();

    // 获取总共的数据
    page.getTotal();

    // 是否存在上一页
    page.hasPrevious();
    // 是否存在下一页
    page.hasNext();
}

5.逻辑删除

  1. 数据库和Java实体类增加字段。
//`deleted` int(0) NULL DEFAULT 0 COMMENT '逻辑删除',

@TableLogic
private Integer deleted;
  1. 新旧版本的配置。

    1. 旧版本,配置拦截器。
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
    
    1. 新版本直接在yaml中进行配置。
    mybatis-plus:
      global-config:
        db-config:
          logic-delete-field: deleted  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以不在实体类上加 @TableLogic)
          logic-delete-value: 1 # 逻辑已删除值(默认为 1)
          logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
    
  2. 局逻辑删除的实体字段名(since 3.3.0,在yaml配置logic-delete-field后可以不在实体类上加 @TableLogic)

  3. 逻辑删除测试代码,delete变为update操作。

// 测试 逻辑删除
@Test
void testDelete01() {
    // 逻辑删除 delete变为
    // UPDATE user SET deleted=1 WHERE id=? AND deleted=0
    int i = userMapper.deleteById(99L);

    // 查询时会添加 WHERE id=? AND deleted=0

    // 分页查询的count(*)操作
    // SELECT COUNT(*) FROM user WHERE deleted = 0
    userMapper.selectById(99L);
    System.out.println(i);
}

6.MybatisPlus中SQL性能分析插件

  1. 旧版本,配置拦截器。
@MapperScans({
        @MapperScan("com.my.mybatisplus.demo01.dao")
})
@Configuration
public class MybatisPlusConfig {
    
    @Bean
    开发和测试环境使用
    @Profile({"dev", "test"})
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        // 设置SQL最大执行时间100秒,超过100秒将不执行当前SQL,并且报错。
        performanceInterceptor.setMaxTime(100);
        // 控制台格式化输出SQL
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }
}
  1. 新版本,官方推荐使用p6spy

    1. 导入依赖。
    <!-- MyBatis-Plus3.2.0以上版本移除了PerformanceInterceptor,可以使用第三方 -->
    <dependency>
        <groupId>p6spy</groupId>
        <artifactId>p6spy</artifactId>
        <version>3.9.1</version>
    </dependency>
    
    1. yaml改变 DataSource的配置。
    spring:
      datasource:
        #driver-class-name: com.mysql.cj.jdbc.Driver
        driver-class-name: com.p6spy.engine.spy.P6SpyDriver
        url: jdbc:p6spy:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF8&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
    
    1. resources下配置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
    

7.MybatisPlus条件查询构造器Wrapper

  1. 查询多个数据selectList()。
// 查询多个数据 selectList()
// 不是null isNotNull
// 大于等于 ge
@Test
void test01() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // WHERE (name IS NOT NULL AND age >= ?)
    wrapper.isNotNull("name")
        .ge("age", "25");
    // 查询 多个数据
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}
  1. 查询一条数据selectOne()。
// 查询一个,如果结果有多个数据报错
// eq
@Test
void test02() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // WHERE (name = ?)
    wrapper.eq("name", "tom");
    // 查询 多个数据
    User user = userMapper.selectOne(wrapper);
    System.out.println(user);
}
  1. count(*)查询。
// count(*) between
@Test
void test03() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // (age BETWEEN ? AND ?)
    wrapper.between("age", 20, 25);
    // 查询 多个数据
    Integer count = userMapper.selectCount(wrapper);
    System.out.println(count);
}
  1. like模糊查询。
// maps
// like
@Test
void test04() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // wrapper.like("name", "t"); ==>> WHERE (name LIKE ?) %t%
    // wrapper.like(true, "name", "t"); ==>> WHERE (name LIKE ?) %t%
    // wrapper.like(false, "name", "t"); ==>> 条件失效
    //wrapper.like(true, "name", "t");

    // wrapper.likeRight("name", "t"); ==>> WHERE (name LIKE ?) t%(String)
    wrapper.likeRight(false, "name", "t");


    // 查询 多个数据 将查询的多个数据封装为Map
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);
}
  1. selectObjs(),将查询结果封装为List(Object),inSql()进行内查询。
// selectObjs()
// inSql 内查询
@Test
void test05() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    // 内查询 (name IN (select name from user where id in (1,2)))
    wrapper.inSql("name", "select name from user where id in (1,2)");

    // 查询 多个数据
    List<Object> objects = userMapper.selectObjs(wrapper);
    objects.forEach(System.out::println);
}
  1. allEq()使用Map作为查询参数。
// allEq()
@Test
void test06() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    Map<String, Object> map = new HashMap<>();
    map.put("name", "tom");
    map.put("age", 12);
    map.put("id", null);

    // wrapper.allEq(map); WHERE (name = ? AND id IS NULL AND age = ?)
    // 默认为true,map中value为null,调用 id IS NULL。
    // false,则忽略map中为null的value
    //wrapper.allEq(map, false); WHERE (name = ? AND age = ?)

    wrapper.allEq((k, v) -> {
        // 返回true时,将才使用map的key和value拼接SQL
        // 相当与 WHERE (name = ?) tom(String)
        return k.equals("name") ? v.equals("tom") : false;
    },map);
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}
  1. func()。
// func 方法(主要方便在出现if...else下调用不同方法能不断链)
//例: func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
@Test
void test07() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    int i = 10;
    wrapper.func(w -> {
        if (i > 10) {
            w.orderByAsc("id");
        }else {
            w.orderByAsc("name");
        }
    });
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}
  1. or()。
@Test
void test08() {
    QueryWrapper<User> wrapper = new QueryWrapper<>();

    // 默认使用and连接
    // WHERE (name = ? OR name = ? AND name = ?)
    //wrapper.eq("name", "tom")
    //.or().eq("name", "bob")
    //.eq("name", "alice");

    // WHERE (name = ? OR (id = ? AND id = ?))
    // or中拼接参数
    wrapper.eq("name", "tom")
        .or(w -> {
            w.eq("id", 1).eq("id", 2);
        });
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);
}
  1. LambdaQueryWrapper。
@Test
void test08() {
    LambdaQueryWrapper<User> w = new LambdaQueryWrapper<>();
    w.eq(User::getAge, "10");
    List<User> users = userMapper.selectList(w);
    users.forEach(System.out::println);
}
  1. 其他查询。
// ne <> 不等于
// ge 大于等于 gt 大于
// le 小于等于 lt 小于
// notBetween("age", 18, 30) --->age not between 18 and 30
// in("age", 1, 2, 3)--->age in (1,2,3)
// notIn("age", 1, 2, 3)--->age not in (1,2,3)
// groupBy("id", "name")--->group by id,name
// orderByAsc("id", "name")--->order by id ASC,name ASC 升序
// orderByDesc("id", "name")--->order by id DESC,name DESC 降序
// having("sum(age) > 10")--->having sum(age) > 10
// having("sum(age) > {0}", 11)--->having sum(age) > 11

8.代码生成器

  1. 配置依赖。
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>

<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

<!-- freemarker模板需要的依赖 -->
<!--<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.28</version>
</dependency>
<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>beetl</artifactId>
    <version>3.0.7.RELEASE</version>
</dependency>-->
  1. 代码生成。
public class CodeGenerator {

    public static void main(String[] args) {
        AutoGenerator ag = new AutoGenerator();

        // 1 全局配置
        GlobalConfig gc = new GlobalConfig();
        // 获取用户工程目录
        String dir = System.getProperty("user.dir");
        System.out.println(dir);
        gc.setOutputDir(dir + "\\src\\main\\java");
        gc.setAuthor("wwt");
        // 生成代码后是否自动打开文件管理器
        gc.setOpen(false);
        // 文件存在是否覆盖
        gc.setFileOverride(false);
        // 去掉Server接口的 I。如默认为IUserService,去掉后为UserService
        //gc.setServiceName("%sServer");
        //gc.setServiceImplName("");
        gc.setIdType(IdType.NONE);
        // 只使用 java.util.date 代替
        gc.setDateType(DateType.ONLY_DATE);
        // 是否生成swagger注释,通过数据库字段注释,生成实体类swagger的注释
        gc.setSwagger2(true);
        ag.setGlobalConfig(gc);

        // 2 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF8&useSSL=false&serverTimezone=Asia/Shanghai");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        ag.setDataSource(dsc);

        // 3 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("demo03");
        pc.setParent("com.my.mybatisplus");
        //pc.setEntity("entity");
        //pc.setMapper("mapper");
        //pc.setService("service");
        //pc.setServiceImpl("service/impl");
        //pc.setController("controller");

        pc.setXml(null);
        ag.setPackageInfo(pc);

        // 4 策略配置
        StrategyConfig strategy = new StrategyConfig();
        // 要生成代码的表
        strategy.setInclude("user");
        // 数据库表映射到实体的命名策略 下划线转驼峰命名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        // 数据库表字段映射到实体的命名策略 下划线转驼峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        // lombok开启注解
        strategy.setEntityLombokModel(true);
        // restful 形式的url
        //strategy.setRestControllerStyle(true);

        // 逻辑删除
        strategy.setLogicDeleteFieldName("deleted");

        // 自动填充
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        strategy.setTableFillList(Arrays.asList(createTime, updateTime));

        // 公共父类
        //strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        //strategy.setSuperEntityColumns("id");

        // 乐观锁
        strategy.setVersionFieldName("version");
        // controller相关
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        ag.setStrategy(strategy);

        // 将mapper.xml生成到resource下
        String templatePath = "/templates/mapper.xml.vm";
        InjectionConfig cfg = new InjectionConfig(){
            @Override
            public void initMap() {

            }
        };

        List<FileOutConfig> list = new ArrayList<>();
        list.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {

                return dir + "/demo03/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(list);
        ag.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        templateConfig.setXml(null);
        ag.setTemplate(templateConfig);

        ag.execute();
    }
}

标签:02,MybatisPlus,name,age,wrapper,查询,Mybatis,new,id
来源: https://www.cnblogs.com/godistance/p/15229150.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有