目录

  • 1、简介
  • 2、快速入门
  • 3、基本使用
  • 传统模式
  • 通用mapper
  • 常用注解
  • 排除非表字段的三种方式
  • 4、MyBatis-Plus查询方法
  • 5、select只列出指定的列
  • 6、condition作用
  • 7、实体作为条件
  • 8、AllEq用法
  • 9、其他使用条件构造器的方法
  • 10、分页
  • 11、更新
  • 12、删除
  • 13、ActiveRecord模式[AR模式]
  • 14、主键策略
  • 15、通用service


1、简介

Mybatis-plus简介:Mybatis增强工具,只做增强,不作改变,简化开发,提高效率。
官网地址:https://mybatis.plus/github项目地址:https://github.com/baomidou/mybatis-plus

框架结构:

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_字段


MP在mybatis启动的时候,它在mybatis的xml和注解注入之后,紧接着反射分析实体,然后注入到底层容器中。就是注入crud之类的。注入之前MP会进行判断,是否已经注入同样的方法,如果注入,就不在注入。它的注入时机在容器启动时,所以MP使用crud、本身是无性能损耗的。

特性:

  • 无侵入,损耗小、强大的CRUD操作
  • 支持Lambda形式调用、支持多种数据库
  • 支持主键自动生成、支持ActiveRecord模式
  • 支持自定义全局通用操作、支持关键词自动转义
  • 内置代码生成器、内置分页插件,内置性能分析插件
  • 内置全局拦截插件、内置sql注入剥离器

2、快速入门

表:

#创建用户表
CREATE TABLE user (
    id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主键',
    name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
    age INT(11) DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
    manager_id BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
    create_time DATETIME DEFAULT NULL COMMENT '创建时间',
    CONSTRAINT manager_fk FOREIGN KEY (manager_id)
        REFERENCES user (id)
)  ENGINE=INNODB CHARSET=UTF8;

#初始化数据:
INSERT INTO user (id, name, age, email, manager_id
	, create_time)
VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL
		, '2019-01-11 14:20:20'),
	(1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553
		, '2019-02-05 11:12:22'),
	(1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385
		, '2019-02-14 08:31:16'),
	(1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385
		, '2019-01-14 09:15:15'),
	(1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385
		, '2019-01-14 09:48:16');

新建一个springboot工程。
依赖:

<!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

配置文件:

#mysql
#mysql8.0的驱动类变成了com.mysql.cj.jdbc.Driver
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-plus?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=123456

logging.level.root=WARN
logging.level.com.example.mybatisplusdemo.dao=TRACE
#级别 内容 换行
logging.pattern.console=%p%m%n

实体类:

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    //直属上级
    private Long managerId;
    private LocalDateTime createTime;
}

dao:

public interface UserMapper extends BaseMapper<User> {
}

启动类:

@MapperScan("com.example.mybatisplusdemo.dao")

测试:

@Test
    void contextLoads() {
    	//查询表中所有记录
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_java_02

3、基本使用

传统模式

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_User_03

通用mapper

BaseMapper类中,含有常用的方法。

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_字段_04

/**
     * 插入
     */
    @Test
    public void insert(){
        User user=new User();
        user.setId(1094592041087729667l);
        user.setName("张三");
        user.setAge(31);
        user.setManagerId(1088250446457389058l);
        user.setCreateTime(LocalDateTime.now());
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }

常用注解

@Data
//数据库的表名是`mp_user`,但是我实体类的名想叫`User`,不想用驼峰命名法,这时就可以用`@TableName`
@TableName("mp_user")
public class User {
    //标识这个字段是表的主键
    @TableId
    private Long id;
    //当前字段和数据库中的字段不一样时,可以直接指定
    @TableField("name")
    private String realName;
    private Integer age;
    private String email;
    //直属上级
    private Long managerId;
    private LocalDateTime createTime;
}

排除非表字段的三种方式

实体类中的remark字段,在表中是不存在的,映射不上是会报错的

@Data
//数据库的表名是`mp_user`,但是我实体类的名想叫`User`,不想用驼峰命名法,这时就可以用`@TableName`
@TableName("mp_user")
public class User {
    //标识这个字段是表的主键
    @TableId
    private Long id;
    //当前字段和数据库中的字段不一样时,可以直接指定
    @TableField("name")
    private String realName;
    private Integer age;
    private String email;
    //直属上级
    private Long managerId;
    private LocalDateTime createTime;


    //备注,这个字段在数据库中是不存在的
    private String remark;
}

解决方式一:添加关键字transient

//备注,这个字段在数据库中是不存在的
//transient关键字标记的成员变量不参与序列化过程。
private transient String remark;

解决方式二:设置为静态变量

private static String remark;

解决方式三:

//备注,这个字段在数据库中是不存在的
    @TableField(exist = false)
    private  String remark;

4、MyBatis-Plus查询方法

普通查询:

@Test
    public void selects(){
        //1、根据主键id查询
//        User user = userMapper.selectById(1087982257332887553l);
//        System.out.println(user);

        //2、根据主键id,批量查询。注意:List.of()在jdk9才有这种写法
//        List<User> users = userMapper.selectBatchIds(List.of(1094592041087729668l, 1094592041087729667l));
//        users.forEach(System.out::println);

        //3、根据指定条件查询数据
        List<User> users = userMapper.selectByMap(Map.of("name", "王天风", "age", 25));
        users.forEach(System.out::println);
    }

条件构造器查询:

//小于lt 小于等于le
    //大于gt 大于等于ge
    //等于eq 不等于ne

EQ 就是 EQUAL等于
NE就是 NOT EQUAL不等于
GT 就是 GREATER THAN大于 
LT 就是 LESS THAN小于
GE 就是 GREATER THAN OR EQUAL 大于等于
LE 就是 LESS THAN OR EQUAL 小于等于
    @Test
    public void selectByWrapper(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        //1、name like "%雨%" and age<40
//        userQueryWrapper.like("name","雨").lt("age",40);
        //2,name like "%雨%" and age between 20 and 40 and email is not null
//        userQueryWrapper.like("name","雨").between("age",20,40).isNotNull("email");
        //3、name like '王%' or age>=25 order by age desc,id asc
//        userQueryWrapper.likeRight("name","王").or().ge("age",25).orderByDesc("age").orderByAsc("id");
        //4、date_format(create_time,'%Y-%m-%d')='2019-02-14' and manager_id in (select id from user where name like '王%')
        //可以避免sql注入的风险date_format(create_time,'%Y-%m-%d')={0}
//        userQueryWrapper.apply("date_format(create_time,'%Y-%m-%d')={0}","2019-02-14").inSql("manager_id","select id from mp_user where name like '王%'");
        //5、name like '王%' and (age<40 or email is not null)
//        userQueryWrapper.likeRight("name","王").and(wq->wq.lt("age",40).or().isNotNull("email"));
        //6、name like '王%' or (age<40 and age>20 and email is not null)
//        userQueryWrapper.likeRight("name","王").or(wq->wq.lt("age",40).
//                gt("age",20).isNotNull("email"));
        //7、(age<40 or email is not null) and name like '王%'
        //or的优先级是小于and的,如果没有前面的括号,结果是不一样的
//        userQueryWrapper.nested(wq->wq.lt("age",40).or().isNotNull("email"))
//                .likeRight("name","王");
        //8、age in (30、31、34、35)
//        userQueryWrapper.in("age",List.of(30,31,34,35));
        //9、limit 1
        userQueryWrapper.in("age",List.of(30,31,34,35)).last("limit 1");

        List<User> users = userMapper.selectList(userQueryWrapper);
        users.forEach(System.out::println);
    }

5、select只列出指定的列

@Test
    public void selectByWrapper(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        //10、默认是显示所有列,select显示指定的列
//        userQueryWrapper.select("id","name").in("age",List.of(30,31,34,35)).last("limit 1");
        userQueryWrapper.in("age",List.of(30,31,34,35)).last("limit 1")
                .select(User.class,info->!info.getColumn().equals("create_time")&&!info.getColumn().equals("manager_id"));
        List<User> users = userMapper.selectList(userQueryWrapper);
        users.forEach(System.out::println);
    }
// 不要某些字段
lambdaQueryWrapper.select(DevicesDeviceDO.class,a->
                !a.getColumn().equals("extra_properties")
                && !a.getColumn().equals("is_deleted")
                && !a.getColumn().equals("update_time")
                && !a.getColumn().equals("create_user_id")
                && !a.getColumn().equals("create_by")
                && !a.getColumn().equals("update_by")
                && !a.getColumn().equals("is_auto")
                && !a.getColumn().equals("running_state")
                && !a.getColumn().equals("sys_tag")
);

6、condition作用

@Test
    void testCondition(){
        String name="王";
        String email="";
        condition(name,email);
    }

    private void condition(String name ,String email){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        //condition作用判断是否满足条件,满足就执行当前语句
        userQueryWrapper.like(!StringUtils.isEmpty(name),"name",name)
                .like(!StringUtils.isEmpty(email),"email",email);
        List<User> users = userMapper.selectList(userQueryWrapper);
        users.forEach(System.out::println);
    }

7、实体作为条件

@Test
    void testCondition1(){
        User user=new User();
        user.setRealName("刘雨红");
        user.setAge(32);
        //实体作为条件,相当于WHERE name=? AND age=?
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(user);
        //默认是等于,如果我想WHERE name like? AND age=?  该怎么办呢?
        //User的name字段,注解@TableField添加属性condition = SqlCondition.LIKE
//        @TableField(value="name",condition = SqlCondition.LIKE )
//        private String realName;
        List<User> users = userMapper.selectList(userQueryWrapper);
        users.forEach(System.out::println);
    }

8、AllEq用法

@Test
    void testAllEq(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        Map<String, Object> params = new HashMap<>();
        params.put("name","王天风");
        params.put("age",null);
        //相当于name = ? AND age = ?
        //如果age为null,相当于name = ? AND age IS NULL,如果想忽略掉为null的allEq(params,false),name = ?
//        userQueryWrapper.allEq(params,false);
        //加入条件,不为name的字段才加入为条件,相当于age IS NULL
        userQueryWrapper.allEq((k,v)->!k.equals("name"),params);

        List<User> users = userMapper.selectList(userQueryWrapper);
        users.forEach(System.out::println);
    }

9、其他使用条件构造器的方法

1、selectMaps:根据条件构造器,查询全部记录

@Test
    void testMap(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
//        select avg(age) avg_age,min(age) min_age,max(age) max_age
//        from user
//        group by manager_id
//        having sum(age) <500
        userQueryWrapper.select("avg(age) avg_age","min(age) min_age","max(age) max_age")
                .groupBy("manager_id").having("sum(age)<{0}",500);
        //查询出的记录,一个记录就是一个map
        List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
        maps.forEach(System.out::println);
    }

2、selectObjs:根据 Wrapper 条件,查询全部记录,注意: 只返回第一个字段的值

@Test
void testObjects(){
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
    //查询id和name两个字段
    userQueryWrapper.select("id","name").like("name","雨").lt("age",40);
    //但是selectObjs只返回第一个字段的值,也就是id的值
    List<Object> maps = userMapper.selectObjs(userQueryWrapper);
    maps.forEach(System.out::println);
}

3、selectCount:根据 Wrapper 条件,查询总记录数

@Test
    void testCount(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like("name","雨").lt("age",40);
        //查询记录数的
        Integer count = userMapper.selectCount(userQueryWrapper);
        System.out.println("总记录数:"+count);
    }

4、selectOne:根据 entity 条件,查询一条记录

@Test
    void testOne(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like("name","刘红雨").lt("age",40);
        //根据条件构造器,查询一条记录
        User user = userMapper.selectOne(userQueryWrapper);
        System.out.println(user.toString());
    }

5、lamdba条件构造器

@Test
    void testlamdba(){
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(User::getRealName,"雨").lt(User::getAge,40);
        List<User> users = userMapper.selectList(lambda);
        for (User user : users) {
            System.out.println(user);
        }
    }
    @Test
    void testlamdba2(){
        List<User> userList = new LambdaQueryChainWrapper<User>(userMapper)
                .like(User::getRealName, "雨").ge(User::getAge, 20).list();
        userList.forEach(System.out::println);
    }

6、自定义sql
方式一:
UserMapper:

public interface UserMapper extends BaseMapper<User> {
    /**
     * 如果自定义的方法还希望能够使用MP提供的Wrapper条件构造器,则需要如下写法
     * 不用加where
     * @param wrappers
     * @return
     */
    @Select("select * from mp_user ${ew.customSqlSegment}")
    List<User> selectAll(@Param(Constants.WRAPPER) Wrapper<User> wrappers);
    /**
     * 和Mybatis使用方法一致
     */
    @Update("update mp_user set deleted=0 where id=#{id}")
    void recover(@Param("id") Long id);
}

使用:

@Test
    void testlamdba(){
        LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
        lambda.like(User::getRealName,"雨").lt(User::getAge,40);
        //使用自定义的sql
        List<User> users = userMapper.selectAll(lambda);
        for (User user : users) {
            System.out.println(user);
        }
    }

方式第二:使用mapper映射文件

配置文件:

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_java_05


映射文件:

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_User_06

10、分页

配置类:

@Configuration
public class MbatisPlusConfig {
    @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;
    }
}

测试:

@Test
    void testPage1(){
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.ge("age",26);

        //第一个参数当前页,第二个参数,每页显示条数,
        // 第三个参数
        // true表示查出所有记录数,再分页:是查询两次
        // SELECT COUNT(1) FROM mp_user WHERE (age >= ?);
        // SELECT id,name AS realName,age,email,manager_id,create_time FROM mp_user WHERE (age >= ?) LIMIT ?
        // false表示只查询分页的数据,查询一次
        // SELECT id,name AS realName,age,email,manager_id,create_time FROM mp_user WHERE (age >= ?) LIMIT ?
        //有些场景就是不需要总数,就可以设置为false,提高性能
        Page<User> userPage = new Page<>(1, 2,true);
        IPage<User> userPage1 = userMapper.selectPage(userPage, userQueryWrapper);
//        userMapper.selectMapsPage()相似的

        System.out.println("总页数:"+userPage1.getPages());
        System.out.println("总记录数:"+userPage1.getTotal());
        List<User> records = userPage1.getRecords();
        records.forEach(System.out::println); 
    }

11、更新

1、updateById:根据主键id去更新一条记录

@Test
    void testUpdate(){
        User user=new User();
        user.setId(1088248166370832385l);
        user.setAge(30);
        int i = userMapper.updateById(user);
        System.out.println("影响记录数:"+i);
    }

2、update:根据实体对象和条件构造器,来更新记录

@Test
    void testUpdateWithWrapper(){
    	//条件构造器
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.eq("name","李艺伟").eq("age",28);
		
		//要更新的内容
        User user = new User();
        user.setEmail("lyw2019@qq.com");
        user.setAge(30);
        //更新
        int i = userMapper.update(user, userUpdateWrapper);
        System.out.println("影响记录数:"+i);
    }

3、lamdba形式

@Test
    void testUpdateWithWrapper1(){
        LambdaUpdateWrapper<User> lambdaUpdate = Wrappers.lambdaUpdate();
        lambdaUpdate.eq(User::getRealName,"李艺伟").eq(User::getAge,30).set(User::getAge,31);

        int update = userMapper.update(null, lambdaUpdate);
        System.out.println("影响记录数:"+update);
    }

12、删除

1、deleteById:根据主键id删除
2、deleteByMap:根据条件删除

@Test
    void deleteByMap(){
        Map<String, Object> columMap = new HashMap<>();
        columMap.put("name","向后");
        columMap.put("age",24);
        int i = userMapper.deleteByMap(columMap);
        System.out.println("影响记录数:"+i);
    }

3、deleteBatchIds:批量删除

13、ActiveRecord模式[AR模式]

实体类

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_spring_07


Mapper要继承BaseMapper

mybatis plus 支持 mongodb 吗 mybatis-plus-plus_java_08


测试:直接使用实体类进行增删改查

@Test
void insert(){
    User u=new User();
    u.setRealName("xxx");
    u.setAge(16);
    u.setEmail("aa@qq.com");
    boolean insert = u.insert();
}

@Test
void  select(){
    User user = new User();
    User user1 = user.selectById(1088248166370832385l);
    System.out.println(user1);
}

14、主键策略

1、IdType.AUTO:数据库ID自增,确保数据库设置了 ID自增 否则无效

@TableId(type = IdType.AUTO)
    private Long id;

更多

@Getter
public enum IdType {
    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。如果手动设置了id,就不生效,就使用设置的id */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_ID}
     */
    @Deprecated
    ID_WORKER_STR(3),
    /**
     * @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
     */
    @Deprecated
    UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}

也可以在配置文件里,设置就不用了每一个实体类都设置主键策略了

mybatis-plus.global-config.db-config.id-type=uuid

15、通用service

public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
@Autowired
    private UserService userService;
    @Test
    void getOne(){
        //false多余一个,不报错,只返回第一个
        User one = userService.getOne(Wrappers.<User>lambdaQuery().gt(User::getAge, 25),false);
        System.out.println(one);

        //传入一个集合,如果对象有id的就是更新,没有的就是新增
//        userService.saveOrUpdateBatch()

        //查询的链式调用
        List<User> userList = userService.lambdaQuery().gt(User::getAge, 25).like(User::getRealName, "雨").list();

        //更新的链式调用
        boolean update = userService.lambdaUpdate().eq(User::getAge, 25).set(User::getAge, 26).update();

        //删除的链式调用
        boolean remove = userService.lambdaUpdate().eq(User::getAge, 25).remove();
    }