欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Mybatis-Plus

程序员文章站 2022-03-20 20:26:33
目 录 1 Mybatis-Plus简介 2 1.1 什么是Mybatis-Plus 2 1.2 为什么要学习Mybatis-Plus 2 1.3 Mybatis-Plus小结 3 2 入门示例 3 2.1 需求 3 2.2 配置步骤说明 3 2.3 配置步骤 3 2.3.1 第一步:搭建环境 3 ......

1、简介

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

框架结构:
Mybatis-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

3、基本使用

传统模式

Mybatis-Plus

通用mapper

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

    /**
     * 插入
     */
    @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
    @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);
    }

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> {
	//不用加where
    @Select("select * from mp_user ${ew.customSqlSegment}")
    List<User> selectAll(@Param(Constants.WRAPPER) Wrapper<User> wrappers);
}

使用:

    @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
映射文件:
Mybatis-Plus

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
Mapper要继承BaseMapper
Mybatis-Plus
测试:直接使用实体类进行增删改查

@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();
    }

本文地址:https://blog.csdn.net/weixin_42412601/article/details/111827181

相关标签: mybatis