Mybatis-plus 笔记整理(一)

 

前言

在很长的时间的项目中,一直在用mybatis-plus操作数据库。感觉mybatis-plus可以作为mybatis的替代品,陪我在数据库的江湖上浪迹天涯。这里,根据日常使用经验,将Mybatis-plus的一些日常操作,以及踩到的坑,整理成博客。方便自己日后项目开发中查阅,也分享给需要的同事和小伙伴。

Mybatis-plus是Mybatis 的增强工具,只做增强不做改变,所以任何能使用mybatis进行crud,并且能支持sql标准的数据库,都可以通过mybatis-plus进行连接。此外,源代码中包含中文注释,可以方便英文理解。

特点

  1. 低侵入性:由于它只是对Mybatis进行增强,不做改变,所以通过它来替换Mybatis不会对当前项目产生任何影响;
  2. 损耗小: 项目启动时会自动注入CRUD,性能基本无损耗,面向对象操作;
  3. 内置通用Mapper: 在Mybatis-plus中,提供通用Mapper接口(BaseMapper<T>)、通用service,可以解决大部分单表操作的CRUD,并且支持强大的条件构造器;
  4. 支持Lambda表达式调用: 通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  5. 支持主键策略: 大部分数据库可以支持四种主键操作,并且包含分布式唯一ID生成器(Sequence),可以自由配置,帮助开发者解决主键生成问题;
  6. 支持ActiveMode模式: 实体类通过继承Model类,就可以通过实体类来完成大多数操作;
  7. 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  8. 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  9. 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  10. 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  11. 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

 

上手准备

 开发环境: IDEA2020.03

 开发框架: SpringBoot 2.3.2.RELEASE

数据库: Oracle 11G

 

Jar包引入

两种方式:

方式一:

<dependency>

                     <groupId>com.baomidou</groupId>

                     <artifactId>mybatis-plus-boot-starter</artifactId>

                     <version>3.4.1</version>

</dependency>

 

方式二:

<dependency>

    <groupId>com.baomidou</groupId>

    <artifactId>mybatis-plus</artifactId>

    <version>3.4.1</version>

</dependency>

 

解释:方式一包含于方式二;也就是说,如果通过方式一的方式引入jar包,它会自动帮你引入方式二中的jar包;如图所示:

 

 

 

 

其他jar包引入:

<!--oracle连接方式-->

              <dependency>

                     <groupId>com.oracle</groupId>

                     <artifactId>ojdbc6</artifactId>

                     <version>11.2.0.3</version>

              </dependency>

<!--Druid 连接池-->

<dependency>

                     <groupId>com.alibaba</groupId>

                     <artifactId>druid-spring-boot-starter</artifactId>

                     <version>1.1.10</version>

              </dependency>

<!—lombok 简化实体类的开发工作-->

              <dependency>

                     <groupId>org.projectlombok</groupId>

                     <artifactId>lombok</artifactId>

                     <version>1.18.16</version>

                     <scope>provided</scope>

              </dependency>

<!—HuTool 提供工具类-->

              <dependency>

                     <groupId>cn.hutool</groupId>

                     <artifactId>hutool-all</artifactId>

                     <version>5.5.7</version>

              </dependency>

 

创建表

CREATE TABLE PUB_USERS

   (ID NUMBER(23,0) NOT NULL ENABLE,

       CODE VARCHAR2(50),

       NAME VARCHAR2(50),

       PWD VARCHAR2(50),

       ADMIN_PWD VARCHAR2(50),

       CONSTRAINT ID_PRIMARY PRIMARY KEY (ID)

)

 

插入数据:

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(1, '111111', '李元芳', '1', '000');

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(2, '111112', '狄仁杰', '1', '000');

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(3, '111113', '诸葛亮', '1', '000');

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(4, '111114', '孙思凯', '1', '000');

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(5, '111115', '蒙犽', '1', '000');

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(6, '111116', '武后主', '1', '000');

INSERT INTO WNSALARYDB.PUB_USERS

(ID, CODE, NAME, PWD, ADMIN_PWD)

VALUES(7, '111117', '李焕珍', '1', '000');

 

配置文件

server:

  # 端口号设置

  port: 8080

spring:

  application:

    name: vue-login

  datasource:

    name: dev_db

    type: com.alibaba.druid.pool.DruidDataSource

    druid:

      driver-class-name: oracle.jdbc.OracleDriver // 加载驱动

      url: jdbc:oracle:thin:@127.0.0.1:1521:orcl // 连接方式

      username: test // 用户名

      password: test // 密码

mybatis-plus:

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

#  config-location: classpath:mybatis/mybatis-config.xml

  global-config: #全局配置

    banner: true #是否需要开启控制台

  configuration:

    # 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射

    map-underscore-to-camel-case: true

    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #设置mybatis 打印日志到控制台

  type-aliases-package: cn.eli.vue.entity

 

注意: 这里有一个配置上的坑,以前我在使用Mybatis时,都会使用mybatis-config.xml配置文件,来设置mybatis的全局配置设置完成之后,我只需要在application.yml配置文件中引入即可(config-location: classpath:mybatis/mybatis-config.xml);如果我这里使用global-config 进行全局配置,那么就不需要在设置config-location,因为两者是真的冲突;

创建实体类

@Data

@EqualsAndHashCode(callSuper = false)

@TableName("PUB_USERS")

@ToString

public class Users  {

 

    private static final long serialVersionUID = 1L;

    // @TableId(type = IdType.ASSIGN_ID)

    private BigDecimal id;

 

    private String code;

 

    private String name;

 

    private String pwd;

 

    private String adminPwd;

 

}

关于adminPwd 字段的说明:

  这里有一点需要注意的是,我们的数据库中的字段要和我们实体类中的字段相对应;比如

  数据库中 code 和 实体类 code;但是数据库中的admin_pwd 字段,和实体类中的adminPwd字段并不相互对应;我们喜欢在java中喜欢用驼峰命名的方式(第一个单词的首字母小写,第二个单词的首字母大写)。但是mybatis-plus还是帮我们映射成功,这是因为我们在配置中存在map-underscore-to-camel-case=true的配置,它就负责帮我们开启驼峰命名的映射规则;

   如果我们需要手动映射,那么我们可以借助注解@TableField() 如下所示:

@TableField(value = "code") // value值即指定需要映射的数据库字段名

    private String code;

 

如果我们的实体类中,存在字段不是数据库中的,如我新增到实体类中的字段:

private String sex;

这个字段在数据库中并不存在,我们不需要它和数据库中的字段映射,那么我们怎么办呢?

可以借助@TableField 的exists 属性,把它设置为false,表示不需要做映射;

注意: TableId 标识本字段为表中主键,它的type属性用于指定主键生成方式;主要有以下四种生成方式: AUTO(数据库ID自增,数据库需要支持主键自增(如MySQL),并设置       主键自增) 

INPUT(用户输入ID,数据类型和数据库保持一致就行) 

ASSIGN_ID //待补充

ASSIGN_UUID // 待补充

     如果用户操作的是oracle数据库,不建议使用提供的自增长方式;后台会报错;

创建Mapper接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper

@Repository

public interface UsersMapper extends BaseMapper<Users> {

}

 

这里,我们可以看一下,当我们继承BaseMapper接口之后,可以获取到通用方法,并且每个方法上都带有中文注释;

如下图所示:

 

创建对应的Controller:

@RestController

@RequestMapping("/users")

public class UsersController {

@Autowired

    private UsersMapper usersMapper;

}

 

注意: 这里我们先跳过创建service及实现类的过程,来说明通用Mapper中的部分用法;

 

通用方法

增加操作

/**

     * 插入一条记录

     *

     * @param entity 实体对象

     */

    int insert(T entity); ---->这里T泛型,会转换成Users类;

 

使用方式:

UsersController:

@RequestMapping("/get/list")

    public void  getUsersList(){

        Users users = new Users();

        users.setId(8);

        users.setCode("111118");

        users.setName("孙尚香");

        users.setPwd("123");

        users.setAdminPwd("1");

        int num = usersMapper.insert(users); //这个返回的参数,表示的是执行成功的条数

}

 

 

大家注意看第一处标红的地方,这里SQL就是我们要执行的插入操作,这就是在application.yml中增加了配置: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 之后的效果;

修改操作

/**

修改方式1:

根据用户id,修改指定字段内容的值;

*/

int updateById(@Param(Constants.ENTITY) T entity);

 

使用方式:

/**

  举个例子,我需要修改 id= 111118的pwd(密码),改为”456”

*/

@RequestMapping("/update/byid")

    public  void updateById(){

        Users users = new Users();

        users.setId(8);

        users.setPwd("456");

        int num = usersMapper.updateById(users); // 返回值依然是修改数据的条数

}

 

/**

根据 whereEntity 条件,更新记录

Params:

entity – 实体对象 (set 条件值,可以为 null)

updateWrapper – 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)

*/

int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

 

 

/**

举个例子,设置id = 8的用户,将其Pwd 字段修改为“789”

*/

@RequestMapping("/update")

    public void  update(){

        /**

         * 这个实体对象,可以为我们需要修改的字段设置值;

         *

         */

        Users users = new Users();

        users.setPwd("789");// 设置需要修改的字段 pwd ,内容为789

        /**

         * 设置查询条件

         *

         */

        QueryWrapper<Users> updateWrapper = new QueryWrapper<>();

        updateWrapper.eq("id",8); // 查找字段id,内容是8

        usersMapper.update(users,updateWrapper); // 设置修改

    }

 

查询操作

单一操作:

/**

     * 根据 ID 查询

     *

     * @param id 主键ID

     */

    T selectById(Serializable id);

 

举例说明:

/**

我想查询,id=8的数据;

*/

@RequestMapping("/select/byid")

    public void  selectById(){

        Integer id = 8;

        Users users = usersMapper.selectById(id);

        System.out.println(users);

}

 

批量查询:

/**

     * 查询(根据ID 批量查询)

     *

     * @param idList 主键ID列表(不能为 null 以及 empty)

     */

    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

 

@RequestMapping("/select/batch")

    public void selectBatchId(){

        List<Integer> ids = Arrays.asList(new Integer[]{1,2,3}); // 设置id集合

        List<Users> users = usersMapper.selectBatchIds(ids);

        users.stream().forEach(System.out::println);

    }

 

设置多项条件进行查询:

/**

     * 查询(根据 columnMap 条件)

     *

     * @param columnMap 表字段 map 对象

     * 这里有一个缺点就是,它只会根据设置的查询条件进行and 拼接,缺乏灵活性;

     */

    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

 

/**

 设置查询条件为 :id = 3 并且 code = “111113”

*/

@RequestMapping("/select/map")

    public void selectBatchByMap(){

        Map<String,Object> queryMap = new HashMap<>();

        queryMap.put("id",3);

        queryMap.put("code","111113");

        List<Users> users = usersMapper.selectByMap(queryMap);

        users.stream().forEach(System.out::println);

}

 

selectBatchByMap 查询条件过于死板,毕竟不能灵活设置查询条件;如果我想随意设置内容,该用什么方法呢?

----- 可以会用selectOne 和  selectList;

selectOne 和 selectList 中传递的参数均为Wrapper<T> queryWrapper ,这个参数可以灵活配置查询条件,可以满足单表查询的所有情况;

和上面update方法使用类似;

selectOne ---> 查询结果类型为Users;

selectList ----> 查询返回结果是List;

@RequestMapping("/select/one")

    public  void selectOne(){

        QueryWrapper<Users> queryWrapper = new QueryWrapper();

        queryWrapper.eq("name","李元芳");// 查询姓名为“李元芳”的用户

        Users users = usersMapper.selectOne(queryWrapper);

        System.out.println("当前查询出的数据为:" + users);

    }

 

    @RequestMapping("/select/list")

    public void selectList(){

        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();

        queryWrapper.like("name","李"); // 查询名字中 包含 “李”的用户

        List<Users> users = usersMapper.selectList(queryWrapper);

        users.stream().forEach(System.out::println);

    }

 

作妖一下,如果我用selectOne 查询,查询出的结果由多条,会产生什么效果呢?如下代码:

        QueryWrapper<Users> queryWrapper = new QueryWrapper();

//        queryWrapper.eq("name","李元芳");// 查询姓名为“李元芳”的用户

        queryWrapper.like("name","李"); // 查询名字中 包含 “李”的用户

        Users users = usersMapper.selectOne(queryWrapper);

        System.out.println("当前查询出的数据为:" + users);

执行结果果断报错,错误内容为:

Expected one result (or null) to be returned by selectOne(), but found: 2

 

如果我需要查询,符合条件的数据有多少条,可以使用selectCount;

@RequestMapping("/select/count")

    public void  selectCount(){

        // 统计pub_users表中一共有多少条数据

        /***

         * 传递参数为 Wrapper<T> queryWrapper,

         * 传递值为null,表示不设置任何查询条件

         */

        Integer count = usersMapper.selectCount(null);

        System.out.println(count);

}

 

分页操作可以使用selectPage 方法,代码如下:

QueryWrapper<Users> queryWrapper = new QueryWrapper<>();

        // Page 中传递的参数为 当前页码  每页大小

        Page<Users> usersPage = usersMapper.selectPage(new Page<Users>(1, 2), queryWrapper); // 分页查询

        List<Users> users = usersPage.getRecords();

        users.forEach(System.out::println);

 

注意: 如果我们执行上述代码,输出操作结果,就会发现,并没有帮我们进行分页,因为这里没有设置查询条件,所以会查询出所有的内容。结果如下:

 

原因是什么呢? 重点是,我们操作的数据库是oracle;当我们在使用selectPage 方法时,底层代码会帮我们在SQL尾部拼接 LIMIT 10 OFFSET 10语句,表示每页显示10条,从下标为10的数据开始显示。但是,oracle并不支持这种语法,所以不会有此操作;

(后面我会补充PageHelper分页的方法)

 

删除数据

 按照ID进行删除---deleteById

 

@RequestMapping("/delete/id")

    public void delete(){

        Integer id = 8;

        int num = usersMapper.deleteById(id); //返回的是成功删除数据的条数

        System.out.println(num);

    }

 

根据ID批量删除---- deleteBatchIds

@RequestMapping("/delete/ids")

    public void deleteByIds(){

        List<Integer> ids =Arrays.asList(new Integer[]{1,2,3,4}); // 设置批量删除id值

        int num = usersMapper.deleteBatchIds(ids);

        System.out.println(num);

}

 

设置多条件删除数据--- deleteByMap

@RequestMapping("/delete/map")

    public void deleteMap(){

        Map<String,Object> map = new HashMap<>();

        map.put("id",8);

        map.put("admin_pwd","1");

        int num = usersMapper.deleteByMap(map); // 设置删除条件

        System.out.println(num);

}

 

自定义设置删除条件----delete

public void delete(){

        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("name","孙尚香");

        int num = usersMapper.delete(queryWrapper);

        System.out.println(num);

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VogtZhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值