MybatisPlus快速入门实践

MybatisPlus快速入门

  • 前言
  • 一、快速入门
    • 1、maven依赖
    • 2、实体类继承 Model<实体>
    • 3、service继承 IService<实体>
    • 4、serviceImpl继承 ServiceImpl<>
    • 5、mapper继承 BaseMapper
    • 6、编写对应的 mapper.xml
  • 二、总体介绍
  • 三、详细介绍
    • 1、自动填充()
      • a.实体类属性上加@TableField(fill=...)
      • b.配置规则
    • 2、乐观锁()
      • a.数据库加一个reversion字段
      • b.实体类加这个字段,并加上@Version注解
      • c.配置乐观锁插件
      • d.测试
    • 3、逻辑删除
      • a.数据库加字段
      • b.实体类属性加@TableLogic
      • c.加配置文件(可忽略,有默认值)
      • d.新增配置类(mybatisplus 3.1以后可省略)
      • d.测试
    • 4、mybatisplus的分页
      • a.配置分页
      • b.测试
    • 5、性能优化,慢sql
      • a.加配置类
      • b.测试
    • 6、自动生成代码
    • 7、条件查询Wrapper
  • 四、常用注解
  • 五、总结


前言

因个人工作原因,需要用到MybatisPlus(之前是用的Mybatis),所以开始学习MP(MybatisPlus)。这篇文章大部分是通过学习哔哩哔哩中的视频“狂神说Java_MyBatisPlus教程”,也添加了一些我个人工作中比较常用的功能,哔哩哔哩的原视频连接是https://www.bilibili.com/video/BV17E411N7KN?p=1
本人水平有限,如有误导,欢迎斧正,一起学习,共同进步!


我个人的github链接(仅供参考): https://github.com/zhengtianliang/mybatisplus-kuang

一、快速入门

1、maven依赖

<dependency>
     <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
     <version>3.0.5</version>
</dependency>

2、实体类继承 Model<实体>

package com.zheng.pojo;

import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author: ZhengTianLiang
 * @date: 2020/12/2  20:42
 * @desc:
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product extends Model<Product> {

    private String  id;
    private String name;
    private Integer age;
    private String email;

}

3、service继承 IService<实体>

package com.zheng.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zheng.pojo.Product;

/**
 * @author: ZhengTianLiang
 * @date: 2020/12/2  20:50
 * @desc:
 */
public interface ProductService extends IService<Product> {
}

4、serviceImpl继承 ServiceImpl<>

serviceImpl继承ServiceImpl

package com.zheng.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zheng.mapper.ProductMapper;
import com.zheng.pojo.Product;
import com.zheng.service.ProductService;
import org.springframework.stereotype.Service;

/**
 * @author: ZhengTianLiang
 * @date: 2020/12/2  20:56
 * @desc:
 */

@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}

5、mapper继承 BaseMapper

package com.zheng.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zheng.pojo.Product;

/**
 * @author: ZhengTianLiang
 * @date: 2020/12/2  20:43
 * @desc:
 */
public interface ProductMapper extends BaseMapper<Product> {
}

6、编写对应的 mapper.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hollycrm.hollycloud.ics.knowledge.admin.mapper.ForbidWordsMapper">


    <!-- 通用查询映射结果 -->
    <resultMap id="forbidResultMap" type="com.hollycrm.hollycloud.ics.knowledge.admin.vo.ForbidWordsVO">
        <id column="id" property="id"/>
        <result column="forbidWords" property="ForbidWords"/>
        <result column="en_code" property="enCode"/>
        <result column="en_full_name" property="enFullName"/>
        <result column="spell_code" property="spellCode"/>
    </resultMap>

    <select id="queryForbidListByCondition" resultMap="forbidResultMap">
        SELECT
        id,
        forbid_words,
        en_code,
        en_full_name,
        spell_code
        FROM
        tb_forbid_words
        <where>
            is_invalid = '1'
            <if test="forbidWords != null and forbidWords != ''">
                AND forbid_words LIKE CONCAT('%',#{forbidWords},'%')
            </if>
        </where>
        ORDER BY create_time DESC
    </select>


</mapper>

二、总体介绍

因为我公司有自己的代码生成模块,所以一直以来没用MP(MybatisPlus)自带的代码生成器。MP的主要功能有:代码生成器、条件构造器、分页插件、自定义ID、字段填充、逻辑删除、慢sql等,我着重介绍一些我比较常使用的功能。更多请参考官方文档:https://baomidou.com/guide/

三、详细介绍

1、自动填充()

自动填充是指,“创建时间”、“修改时间”这些字段的自动填充(是填充至实体的,而非数据库设置默认值)。

a.实体类属性上加@TableField(fill=…)

其中@TableField(fill = FieldFill.INSERT) 代表着这个属性在新增的时候作某种操作(由规则中配置的什么操作,就做什么操作); @TableField(fill = FieldFill.INSERT_UPDATE)代表新增、更新的时候,做某种操作,由配置的规则决定。

package com.zheng.pojo;

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

import java.time.LocalDateTime;

/**
 * @author: ZhengTianLiang
 * @date: 2020/11/14  22:59
 * @desc: 用户表
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime modifyTime;
}

b.配置规则

是配置具体的当作新增、更新动作的时候做的事情

package com.zheng.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.time.LocalDateTime;
import java.util.Date;

/**
 * @author: ZhengTianLiang
 * @date: 2020/11/17  21:58
 * @desc: 规定一下update的规则
 */

@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {

    // 插入填充时的策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insertFill ");
        this.setFieldValByName("createTime", LocalDateTime.now(),metaObject);
        this.setFieldValByName("modifyTime", LocalDateTime.now(),metaObject);
    }

    // 更新填充时的策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start updateFill ");
        this.setFieldValByName("modifyTime",LocalDateTime.now(),metaObject);
    }
}

2、乐观锁()

正常来讲,数据库设计的时候,除了业务字段以外,一般都会有一些公共的字段:主键ID、创建时间、修改时间、状态、版本号。版本号这个字段主要是用于并发控制的:
具体做法一直是为每张表设置一个数据库版本字段(Version),每次更新操作都要比较这个Version,如果版本号不匹配则说明数据已被他人修改,提示用户重新加载数据。

实现步骤:

a.数据库加一个reversion字段

alter table tb_user add reversion int(11) default 0 comment '乐观锁' after name;

b.实体类加这个字段,并加上@Version注解

package com.zheng.pojo;


import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

/**
 * @author: ZhengTianLiang
 * @date: 2020/11/14  22:59
 * @desc: 用户表
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    // 乐观锁
    @Version
    private Integer reversion;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime modifyTime;
}

c.配置乐观锁插件

springboot的话,返回一个OptimisticLockerInterceptor 的bean对象

package com.zheng.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author: ZhengTianLiang
 * @date: 2020/11/17  22:17
 * @desc: 这是测试乐观锁的时候用的
 */

@Component
@EnableTransactionManagement // 这个是默认开启的,可以不写
@MapperScan(value = "com.zheng.mapper") // 这个本来是写在启动类上的,我给挪到这个config里面了
                                        // 注意,要想使用mybatisplus,这个mapperScan必不可少
public class MybatisPlusConfig {

    // 返回一个乐观锁组件
    @Bean
    public OptimisticLockerInterceptor getOptimisticLockerInnerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

d.测试

注意,是先userMapper.selectById(),必须先定位到数据,

// 测试乐观锁
@Test
public void test03(){
    User user = userMapper.selectById(7L);
    // SELECT id,name,age,email,reversion,create_time,modify_time FROM user WHERE id=?
    user.setName("lsdjd");

    //UPDATE user SET name=?, age=?, reversion=?, modify_time=? WHERE id=? AND reversion=?
    userMapper.updateById(user);
}

3、逻辑删除

日常开发中,除非真的是一些脏数据,否则一般很少物理删除,几乎都是逻辑删除。
物理删除:是说我直接将这条数据从数据库里删除了
逻辑删除:是说我将这条数据设置成失效的状态,我查询的时候只查状态有效的数据

a.数据库加字段

alter table tb_user add status int default 1 comment '状态,0无效,1有效' after reversion;

b.实体类属性加@TableLogic

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(value = "id",type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;

    // 乐观锁
    @Version
    private Integer reversion;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime modifyTime;

    // 状态,0无效,1有效
    @TableLogic
    private Integer status;
}

c.加配置文件(可忽略,有默认值)

默认1是已删除,0是未删除。mybatis-plus.global-config.db-config.logic-delete-value属性。

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

#by zhengkai.blog.csdn.net
#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      logic-delete-value: 0   # 已删除的,0(默认为1)
      logic-not-delete-value: 1 # 1是有效的  未删除的(默认为0)

d.新增配置类(mybatisplus 3.1以后可省略)

@Bean
public ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
}

d.测试

boolean a = userService.removeById("10"); 
// 测试的sql语句
UPDATE user SET status=1 WHERE name = ? AND status=0

// 调用查询的时候,也会自动的加上delete = 0 
SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 LIMIT ?

4、mybatisplus的分页

a.配置分页

//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;
    }
}

b.测试

// 测试分页
@Test
public void test04(){
    Page page = new Page<>(1, 5);
    userMapper.selectPage(page,null);

    page.getRecords().forEach(System.out::println);
    System.out.println("总条数为:"+page.getTotal());

}

5、性能优化,慢sql

慢sql的作用就是监控sql的执行,可以指定一个超时时间,假设是5毫秒,那么全部的sql,只要执行超过5毫秒,就会报错,然后定位sql。通过执行计划(explain)看看原因。执行计划中有两点比较重要,一个是有没有走索引,走索引比全表扫描好;另一个是查询所涉及的行数,这个是越小越好。通过执行计划来定位问题,帮助我们优化sql,减少响应时间,提高用户体验度。

a.加配置类

package com.zheng.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author: ZhengTianLiang
 * @date: 2020/11/17  22:17
 * @desc: 这是测试慢sql的时候用的
 */

@Component
@EnableTransactionManagement // 这个是默认开启的,可以不写
@MapperScan(value = "com.zheng.mapper") // 这个本来是写在启动类上的,我给挪到这个config里面了
// 注意,要想使用mybatisplus,这个mapperScan必不可少
public class MybatisPlusConfig {


    /**
     * 配置慢sql用的 bean对象
     */
    @Bean
    @Profile({"dev", "test"}) // 设置  是dev、test环境下才会开启,保证线上环境的效率
    public PerformanceInterceptor getPerformanceIntercepter() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100); // 设置sql执行的最大时间,超过了这个时间就会报错,单位是毫秒
        performanceInterceptor.setFormat(true); // 设置sql的格式化

        return performanceInterceptor;
    }


}

b.测试


@Test
public void test01(){
    List users = userMapper.selectList(null);
    users.forEach(System.out::println);
}


 Time:26 ms - ID:com.zheng.mapper.UserMapper.selectList
Execute SQL:
    SELECT
        id,
        name,
        age,
        email,
        reversion,
        create_time,
        modify_time,
        status 
    FROM
        user

6、自动生成代码

MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

package com.zheng;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: ZhengTianLiang
 * @date: 2020/11/23  21:35
 * @desc: 测试MybatisPlis的代码生成器   测试类
 */

@SpringBootTest
public class GenerateCode {

    public static void main(String[] args) {
        // 需要构建一个代码生成器对象
        AutoGenerator autoGenerator = new AutoGenerator();

        // 配置策略
        // 1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        System.out.println("项目的路径是:"+projectPath);
        gc.setOutputDir(projectPath+"src/main/java"); // 生成的代码的存放路径
        gc.setAuthor("ZhengTianLiang_mybatis_plus_auto"); // 设置作者
        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的注解

        autoGenerator.setGlobalConfig(gc); // 将全局配置set进代码生成器对象中去

        // 2、设置数据源
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis_kuang?serverTimezone=UTC&useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("123456");
        dataSourceConfig.setDbType(DbType.MYSQL); // 设置数据源 mysql数据库

        autoGenerator.setDataSource(dataSourceConfig); // 将数据源set进代码生成器对象中去

        // 3、包的位置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setModuleName("blog"); // 生成的代码都在这个包下面
        packageConfig.setParent("com.zheng"); // 设置包名
        packageConfig.setEntity("entity"); // 设置实体类的包的名
        packageConfig.setMapper("mapper"); // 设置mapper的名
        packageConfig.setService("service"); // 设置service
        packageConfig.setController("controller"); // 设置controller

        autoGenerator.setPackageInfo(packageConfig); // 将包的设置set进代码生成器对象中去

        // 策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("clas","product"); // 设置要生成的表名,可以多个,只生成这个对应的表
        strategyConfig.setNaming(NamingStrategy.underline_to_camel); // 包的命名规则(下划线变驼峰)
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); // 列的命名规则(下划线变驼峰)
        // strategyConfig.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategyConfig.setEntityLombokModel(true); // 实体上是否用lombok注解来简化代码
        strategyConfig.setRestControllerStyle(true); // 开启restful的驼峰命名格式

        // 设置逻辑删除的字段
        strategyConfig.setLogicDeleteFieldName("deleted");
        // 乐观锁的配置
        strategyConfig.setVersionFieldName("version");
        // 设置url的一个风格,可以不设置     localhost:8080/hello_id_2  比较清晰一些
        strategyConfig.setControllerMappingHyphenStyle(true);

        // 自动填充的配置
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);// 创建时间,创建的时候自动填充
        TableFill modifyTime = new TableFill("modify_time", FieldFill.INSERT_UPDATE); // 修改时间,创建和更新的时候自动填充

        // 将上面的自动填充  set进策略配置中
        List tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(modifyTime);
        strategyConfig.setTableFillList(tableFills);

        autoGenerator.setStrategy(strategyConfig);

        // 执行
        autoGenerator.execute();

    }
}

7、条件查询Wrapper

我个人的理解是,这个Wrapper有点类似于SpringDataJPA的criteriaBuilder,都是不用自己手写sql,通过方法来拼接出来的sql。
criteriaBuilder.eq、.like、.gt等等。
criteriaBuilder的例子:

public Page getGroupMemberCardList(Long groupId, String keyWord,
                                                           GroupMemberCardAccountType accountType, Integer page, Integer size) {
    String sortType = "desc";
    String sortField = "createTime";
    // 生成排序分页规则
    PageRequest pr = CareerUtil.getPage(sortType, sortField, page, size);
    Page cardAccountPage = groupMemberCardAccountRepository.findAll(new Specification() {
        @Nullable
        @Override
        public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
            List list = new ArrayList();
            list.add(criteriaBuilder.equal(root.get("groupMemberCard").get("group").get("id").as(Long.class), groupId));

            if (accountType != null) {
                list.add(criteriaBuilder.equal(root.get("accountType").as(GroupMemberCardAccountType.class), accountType));
            }
            if (StringUtils.isNotEmpty(keyWord)) {
                Predicate p1 = criteriaBuilder.like(root.get("groupMemberCard").get("memberName").as(String.class), "%" + keyWord + "%");
                Predicate p2 = criteriaBuilder.like(root.get("groupMemberCard").get("cardNo").as(String.class), "%"+keyWord +"");
                Predicate p3 = criteriaBuilder.like(root.get("groupMemberCard").get("user").get("telphone").as(String.class), "%" + keyWord + "%");
                list.add(criteriaBuilder.or(p1,p2,p3));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        }
    }, pr);
    return cardAccountPage;
}

MybatisPlus的Wrapper也是一样:

 	// 查询列表
    @Test
    public void test01(){
        // 查询name = Jone ,age 大于2的 email不为空的user对象
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.isNotNull("email")
                .eq("name","Jone")
                .gt("age",2);

        //userMapper.selectList(wrapper); // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND email IS NOT NULL AND name = ? AND age > ?
        userService.list(wrapper); // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND email IS NOT NULL AND name = ? AND age > ?
    }

    // 查询单个
    @Test
    public void test02(){
        // 查询名字是Jone 的对象,
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("name","Jone");

       // User one = userService.getOne(wrapper); // 即使结果集有多个,也不报错,但是只会展示第一个  SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND name = ?
        User one = userMapper.selectOne(wrapper); // 结果集是多个的话,报错  SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND name = ?
        System.out.println(one);
    }

    @Test
    public void test03(){
        // 查询年龄在20-30之间的用户
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.between("age",10,20);

        //Integer integer = userMapper.selectCount(wrapper); // SELECT COUNT(1) FROM user WHERE status=1 AND age BETWEEN ? AND ?
        int integer = userService.count(wrapper);  // SELECT COUNT(1) FROM user WHERE status=1 AND age BETWEEN ? AND ?
        System.out.println(integer);
    }

    // 模糊查询
    @Test
    public void test04(){
        // 查询名字中不带e的,并且email是以a开头的  用户
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.notLike("name","e") // AND name NOT LIKE '%e%'
                .likeLeft("email","a") // AND email LIKE '%a'
                .likeRight("age","1"); // AND age LIKE '1%'

        //List> maps = userMapper.selectMaps(wrapper);// SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND name NOT LIKE ? AND email LIKE ? AND age LIKE ?
        Map maps = userService.getMap(wrapper); // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND name NOT LIKE ? AND email LIKE ? AND age LIKE ?

    }

    // 子查询
    @Test
    public void test05(){
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.inSql("id","select id from user where id <3");

        // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND id IN (select id from user where id <3)
        //List objects = userMapper.selectObjs(wrapper); // 这个结果集是一个list   查到了2个user对象
        //objects.forEach(System.out::println);

        // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 AND id IN (select id from user where id <3)
        Object obj = userService.getObj(wrapper); // 这个结果集是一个对象,  查到了2个对象,但是只展示第一个对象
        System.out.println(obj);
    }

    // 排序
    @Test
    public void test06(){
        // 通过name、id降序排列
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.orderByDesc("name","id");

        //List users = userMapper.selectList(wrapper); // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 ORDER BY name DESC , id DESC
        List users = userService.list(wrapper); // SELECT id,name,age,email,reversion,create_time,modify_time,status FROM user WHERE status=1 ORDER BY name DESC , id DESC
        System.out.println(users);
    }
 
  

四、常用注解

@TableName(value = “user”) 用于数据库名和实体类不匹配的情况
@TableId(value=‘主键字段’,type=‘主键生成策略’)
@TableName(value=‘数据库表名’)
@TableField(value=‘数据库字段名’,exist = false,select = false)
exist=false 表示不是数据库字段
select = false 表示sql不查询这个字段

@Version 乐观锁
@EnumValue 通用枚举类注解,将数据库字段映射成实体类的枚举类型成员变量
@TableLogic 映射逻辑删除,注释掉这个@TableLogic,去执行mapper.deleteById()的话,就会物理删除

值得注意的是,在@TableId(type=‘主键生成策略’)假设你是MySql数据库,那么你可以选择 @TableId(value = “id”, type = IdType.AUTO);若你是Oracle数据库的话,需要换成@TableId(value = “id”, type = IdType.INPUT),切身踩坑,希望大家可以避免我的问题。


五、总结

总的来说,有之前的ORM框架(Hibernate,Mybatis)的相关经验的话,还是比较容易上手的。无论是Hibernate、Mybatis、MybatisPlus、SpringDataJPA这些框架是哪种,但是底层肯定是对java的JDBC的封装,越来越好的框架是为了帮助我们节约开发时间成本,提高效率。

你可能感兴趣的:(java,mybatis)