MybatisPlus快速入门

1.MybatisPlus简介

  MybatisPlus(简称MP)是Mybatis增强工具,增强不做改变,简化开发,官网 http://mp.baomidou.com/

2.特性

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作

强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求

支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库

支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动

支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD操作

支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词

内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用

内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List 查询

内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询

内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD操作支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List 查询

3.快速入门

3.1 创建数据库

数据库名称mybatis_plus

3.2 创建表

CREATE TABLE user
(
    id BIGINT(20) NOT NULL COMMENT '主键ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT(11) NULL DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (id)
);

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

3.3 创建springboot项目

导入maven依赖

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>1.18.20</version>
        </dependency>

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

配置mysql

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding-utf-8
spring.datasource.username=root
spring.security.user.password=root
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

创建实体类User

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

创建UserMapper继承BaseMapper

public interface UserMapper extends BaseMapper<User> {
}

在启动类添加@MapperScan("com.gh")

3.4 基本crud

查询所有

@Test
    void testSelect() {
        List<User> list = userMapper.selectList(null);
        list.forEach(System.out::println);
    }

添加

    @Test
    public void insert() {
        User user = new User();
        user.setName("建国");
        user.setAge(74);
        user.setEmail("jianguo@qq.com");
        userMapper.insert(user);
    }

查询

    @Test
    public void TestSelect() {
        User user = userMapper.selectById(1);
        System.out.println(user);
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 4));
        users.forEach(System.out::println);
    }

修改

    @Test
    public void testUpdate() {
        User user = new User();
        user.setId(1L);
        user.setAge(74);
        int result = userMapper.updateById(user);
        System.out.println(result);
    }

删除

    @Test
    public void delete(){
        int result = userMapper.deleteById(1L);
        System.out.println(result);
    }

 通用service

编写UserService接口,继承IService接口

public interface UserService extends IService<User> {
}

编写UserServiceImpl实现类继承ServiceImpl类,实现UserService接口

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

查询总数

    @Test
    public void count() {
        int count = userService.count(null);
        System.out.println(count);
    }

批量添加

    @Test
    public void saveBatch() {
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            User user = new User();
            user.setName("张三" + i);
            user.setAge(20 + i);
            list.add(user);
        }
        boolean flag = userService.saveBatch(list);
        System.out.println(flag);
    }

4.自定义mapper

当通用mapper无法满足我们的需求时,我们可以自定义基于mapper接口的xml文件,并在xml文件中配置SQL语句

4.1 定义接口方法

在UserMapper里定义方法

    List<User> selectAllByName(String name);

4.2 创建xml文件

在resources目录下创建mapper/UserMapper.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.gh.mpdemos.mapper.UserMapper">
    <sql id="BaseColumn">
        a.id AS id,
        a.name AS name,
        a.age AS age,
        a.email AS email
    </sql>
    <select id="selectAllByName" resultType="User">
        select <include refid="BaseColumn"/>
        from user AS a
        where a.name = #{name}
    </select>
</mapper>

在配置文件进行xml扫描

mybatis-plus.mapper-locations=classpath:mapper/*.xml

4.3 创建测试类

    @Test
    public void testSelectByName(){
        List<User> list = userMapper.selectAllByName("Jack");
        list.forEach(System.out::println);
    }

5.常用注解

5.1 @TableName

 value属性

实体类的名称是User,数据库的表名是t_user,此时我们需要在实体类上加上@TableName注解

@TableName(value = "t_user")
public class User {
}

5.2 @TableId

type属性

type属性可以指定id生成策略,这里的指定雪花算法生成

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

5.3 @TableField

value属性

可以通过value属性指定字段名

    @TableField(value = "username")
    private String name;

5.4 自动填充

 在数据库添加上create_time和update_time两个字段,并在实体类加上如下代码

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

配置自动填充插件

在字段上面加上注解@TableField(fill=FillField.INSERT) 添加时,@TableField(fill=FillField.UPDATE)修改时候,时间跟着修改

必备条件:创建类MyMetaObjectHandler实现类MetaObjectHandler,重写insertFill和updateFill方法,具体写法如下

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", LocalDateTime.now(),metaObject);
        this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
    }
}

5.5 @TableLogic

 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍然能够看到此条数据记录,使用场景:可以进行数据恢复。

首先在数据库创建字段is_deleted,类型为tinyint然后在实体类添加属性deleted

    @TableLogic
    @TableField(value = "is_deleted")
    private Boolean deleted;

然后在配置类添加mybatisplus逻辑删除插件,注意:mp版本为3.3.*的省去这一步

0代表未删除,1代表已删除

@Configuration
public class MpConfig {

    /**
     * 逻辑删除
     * @return
     */
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }
}

6.分页插件

6.1 配置

在配置文件中进行如下配置

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

新建一个mybatis的数据源配置文件,代码如下

@Configuration
public class DataSourceConfig {
    @Autowired
    private PaginationInterceptor paginationInterceptor;
    @Primary
    @Bean(name = "helmetSqlSessionFactory")
    public SqlSessionFactory helmetSqlSessionFactory( DataSource helmetDataSource)
            throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(helmetDataSource);
//        关键代码 设置 MyBatis-Plus 分页插件
        Interceptor[] plugins = {paginationInterceptor};
        sqlSessionFactory.setPlugins(plugins);
        return sqlSessionFactory.getObject();
    }
}

6.2 分页插件使用

 page里的第一个参数代表当前页,第二个参数代表每页显示的条数

    @Test
    public void selectByPage(){
        Page<User> page=new Page<>(1,2);
        userService.page(page, null);
        page.getRecords().forEach(System.out::println);
        long total = page.getTotal();
        System.out.println(total);
    }

关于xml中的分页,我们只需在接口方法中传递page对象就可以了,mybatisplus会自动帮我们进行分页

    IPage<User> selectPageVo(Page<?> page,Integer age);

对应的xml语句如下,不需要自己进行手动分页

    <select id="selectPageVo" resultType="com.gh.mpdemos.entity.User">
        select <include refid="BaseColumn"></include>
        from user
        where age > #{age}
    </select>

7.乐观锁

数据库中添加version字段:取出记录时,获取当前version,更新时,version + 1,如果where语句中的version版本不对,则更新失败

    @Version
    private Integer version;

添加乐观锁插件

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }

8.条件构造器

8.1 wrapper家族

在MP中我们可以使用通用Mapper(BaseMapper)实现基本查询,也可以使用自定义Mapper(自定义XML)来实现更高级的查询。当然你也可以结合条件构造器来方便的实现更多的高级查询。

Wrapper : 条件构造抽象类,最顶端父类  
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper

8.2 QueryWrapper

查询组装条件

    /**
     * 查询名字中包含n,年龄大于等于10且小于等于20,email不为空的用户
     */
    @Test
    public void test1(){
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.like("name","n");
        queryWrapper.le("age",20);
        queryWrapper.ge("age",10);
        queryWrapper.isNotNull("email");
        List<User> list = userService.list(queryWrapper);
        list.forEach(System.out::println);
    }

排序组装条件

    /**
     * 按年龄降序查询用户,如果年龄相同则按id升序排列
     */
    @Test
    public void test2() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("id");
        List<User> list = userService.list(queryWrapper);
        list.forEach(System.out::println);
    }

删除组装条件

    /**
     * 删除email为空的数据
     */
    @Test
    public void test3() {
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.isNull("email");
        boolean remove = userService.remove(queryWrapper);
        System.out.println(remove);
    }

 条件的优先级

    /**
     * 查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 user@atguigu.com
     */
    @Test
    public void test4() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name", "n")
                .and(i -> i.lt("age", 18).or().isNull("email"));//lambda表达式的逻辑优先计算
        User user = new User();
        user.setAge(18);
        user.setEmail("user@atguigu.com");
        boolean update = userService.update(user, queryWrapper);
        System.out.println(update);
    }

组装select子句

    /**
     * 查询所有用户的用户名和年龄
     */
    @Test
    public void test5(){
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.select("name","age");
        List<Map<String, Object>> list = userMapper.selectMaps(queryWrapper);
        list.forEach(System.out::println);
    }

实现子查询

    /**
     * 查询id不大于3的所有用户的id列表
     */
    @Test
    public void test6() {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("id", "select id from t_user where id<=3");
        List<User> list = userMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

对应的sql语句是

SELECT id,name,age,email,create_time,update_time,is_deleted AS deleted FROM t_user WHERE is_deleted=0 AND (id IN (select id from t_user where id<=3)) 

8.3 UpdateWrapper

查询结果SQL语句为:UPDATE t_user SET age=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age < ? OR email IS NULL)) ,不会更新时间,解决办法是在update方法中添加user对象。

    /**
     * 查询名字中包含n,且(年龄小于18或email为空的用户),并将这些用户的年龄设置为18,邮箱设置为 user@atguigu.com
     */
    @Test
    public void test7() {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper
                .set("age",18)
                .set("email","user@atguigu.com")
                .like("name", "n")
                .and(i -> i.lt("age", 18).or().isNull("email"));//lambda表达式的逻辑优先计算
        boolean update = userService.update(updateWrapper);
        System.out.println(update);
    }

condition

    /**
     * 查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
     */
    @Test
    public void test8() {
        String name = "names";
        Integer ageBegin = 10;
        Integer ageEnd = 20;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(name)) {
            queryWrapper.like("name", name);
        }
        if (ageBegin != null) {
            queryWrapper.gt("age", ageBegin);
        }
        if (ageEnd != null) {
            queryWrapper.lt("age", ageEnd);
        }
        List<User> list = userService.list(queryWrapper);
        list.forEach(System.out::println);
    }

8.4 LambdaQueryWrapper

基本用法,防止字段写错而出现问题

    /**
     * 查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
     */
    @Test
    public void test9() {
        String name = "names";
        Integer ageBegin = 10;
        Integer ageEnd = 20;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(name), User::getName, name);
        queryWrapper.gt(ageBegin != null, User::getAge, ageBegin);
        queryWrapper.lt(ageEnd != null, User::getAge, ageEnd);
        List<User> list = userService.list(queryWrapper);
        list.forEach(System.out::println);
    }

一点点学习,一丝丝进步。不懈怠,才不会被时代所淘汰!

原文地址:https://www.cnblogs.com/fqh2020/p/14918401.html