• 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);
        }

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

  • 相关阅读:
    好用的电脑软件
    Swoft HTTPServer 使用经验分享
    nginx location proxy_pass详解
    kafka文档
    es 安装
    rabbitmq 文档
    Mysql百万级数据迁移,怎么迁移?实战过没?
    用bat脚本在Windows上实现微信多开
    vscode保存时自动格式化
    引入bootstrap
  • 原文地址:https://www.cnblogs.com/fqh2020/p/14918401.html
Copyright © 2020-2023  润新知