MyBatisPlus讲解(一)

一、MyBatis-Plus简介

1、简介

**MyBatis-Plus (简称 MP)**是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为 简化开发、提高效率而生。Mybatis-Plus提供了通用的Mapper和Service,**可以在不编写任何SQL语句的前提下,快速的实现单表的增删改查(CURD),批量,逻辑删除,分页等操作。**只要把MyBatis-Plus的特性到优秀插件,以及多数据源的配置进行详细讲解。
在这里插入图片描述

2、特性

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求。
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题。
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强 大的 CRUD 操作。
支持自定义全局通用操作:支持全局通用方法注入(Write once, use anywhere )。
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等 同于普通 List 查询。
分页插件支持多种数据库:支持 MySQL、 MariaDB、Oracle、 DB2、 H2、 HSQL、SQLite、 Postgre、SQLServer 等多种数据库。
内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出 慢查询。
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防 误操作。

3、框架结构

在这里插入图片描述

4、代码及文档地址

官方地址: http://mp.baomidou.com
代码发布地址:Github: https://github.com/baomidou/mybatis-plus
Gitee: https://gitee.com/baomidou/mybatis-plus
文档发布地址: https://baomidou.com/pages/24112f

二、入门案例

1、创建数据库及表

创建数据库如下:

CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; use `mybatis_plus`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名 ',
`age` int(11) DEFAULT NULL COMMENT '年龄 ',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱 ',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

添加下面的数据:

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');

2、引入数据库依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

三、编写代码

1、编写application.yml文件

spring:
  datasource:
  # 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
    # 配置连接数据库信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
    username: root
    password: root
#mybatis:
#  mapper-locations: classpath:mapper/*.xml  #对应mapper映射xml文件所在路径
#  type-aliases-package:   #对应实体类路径
# 配置MyBatis日志
mybatis-plus:
  mapper-locations: classpath*:com/qcby/mapper/*.xml
  type-aliases-package: com.qcby.entity
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2、启动类添加扫描注解

在这里插入图片描述

3、添加实体

package com.qcby.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user") // 确保表名正确
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

使用ait+7查看该实体类中的get和set方法,并且进行查看:
在这里插入图片描述
BaseMapper是MyBatis-Plus提供的模板mapper,其中包含了基本的CRUD方法,泛型为操作的 实体类型

public interface UserMapper extends BaseMapper<User> {
}

4、添加日志

在application.yml中配置日志输出

mybatis-plus:
  mapper-locations: classpath*:com/qcby/mapper/*.xml
  type-aliases-package: com.qcby.entity
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

一、基本CRUD

当我使用MybatisPlus的时候,需要自己定义Mapper的接口用于继承BaseMapper,其中BaseMapper中有以下的方法:

public interface BaseMapper<T> extends Mapper<T> {
    int insert(T entity);

    int deleteById(Serializable id);

    int deleteById(T entity);

    int deleteByMap(@Param("cm") Map<String, Object> columnMap);

    int delete(@Param("ew") Wrapper<T> queryWrapper);

    int deleteBatchIds(@Param("coll") Collection<?> idList);

    int updateById(@Param("et") T entity);

    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

    T selectById(Serializable id);

    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

    default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
        List<T> list = this.selectList(queryWrapper);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0L;
    }

    Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper);
}

1、增加

MyBatisPlus中的方法中只有下面这一个增加好的方法:

    int insert(T entity);

测试方法:

    @Test
    public void testInsert(){
        User user = new User();
        user.setName("张三");
        user.setAge(23);
//        user.setEmail("asdasdas@163.com");
        int rows = userMapper.insert(user);
// SQL: INSERT INTO user ( name, age, email ) VALUES ( ?, ?, ? )
    }

上面方法使用的雪花算法,添加的id值不是随之之前的自动递增的,而是雪花算法计算出来的。
雪花算法(Snowflake) 是 Twitter 开源的分布式ID生成算法,生成的ID是64位的Long类型数字,结构如下:

0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000

1位:符号位(始终为0)

41位:时间戳(毫秒级,可用69年)

10位:机器ID(5位数据中心 + 5位机器ID)

12位:序列号(每毫秒可生成4096个ID)

可以在application.yaml文件中进行配置,配置如下:

mybatis-plus:
  global-config:
    db-config:
      id-type: assign_id  # 使用雪花算法生成ID
      # 其他可选值: 
      # auto: 数据库自增
      # none: 未设置主键类型
      # input: 用户输入ID
      # assign_id: 雪花算法
      # assign_uuid: UUID

第二种方式如下:

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)  // 只需要这个注解即可
    private Long id;
    
    private String name;
    private Integer age;
    private String email;
}

插入后ID会自动回填到实体对象中

2、删除

MybatisPlus中的删除的方法一共有以下的几种方法:

int deleteById(Serializable id);

int deleteById(T entity);

int deleteByMap(@Param("cm") Map<String, Object> columnMap);

int delete(@Param("ew") Wrapper<T> queryWrapper);

int deleteBatchIds(@Param("coll") Collection<?> idList);

其中的第一个是根据id进行删除:
等同于下面的情况:

int rows = userMapper.deleteById(4L);
// SQL: DELETE FROM user WHERE id = 4

其中的第二个是根据id进行删除:
等同于下面的情况:

User user = new User();
user.setName("张三");
int rows3 = userMapper.deleteById(user);
// SQL: DELETE FROM user WHERE name = '张三'

其余的使用方式:

int rows1 = userMapper.delete(new QueryWrapper<User>().eq("name", "张三"));
// SQL: DELETE FROM user WHERE name = '张三'
int rows2 = userMapper.deleteBatchIds(Arrays.asList(5L, 6L));
// SQL: DELETE FROM user WHERE id in (5,6)
int rouw3 = userMapper.deleteByMap(new HashMap<String, Object>(){
     {
        put("name", "张三");
        put("age", 23);
       }
});
// SQL: DELETE FROM user WHERE name = '张三' and age = 23

在这里插入图片描述

3、修改

修改有下面的方法:

    int updateById(@Param("et") T entity);

    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);

测试方法如下:

    public void testUpdate(){
        userMapper.updateById(new User(4L, "admin", 22, "asadasdas@163.com"));

        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.set("age", 30)                    // 设置字段
                .set("email", "new@email.com")     // 设置字段
                .eq("name", "张三");                // 设置条件

        int rows = userMapper.update(null, wrapper);
// SQL: UPDATE user SET age=30, email='new@email.com' WHERE name = '张三'
    }

4、查询

    T selectById(Serializable id);

    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

    default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
        List<T> list = this.selectList(queryWrapper);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

    default boolean exists(Wrapper<T> queryWrapper) {
        Long count = this.selectCount(queryWrapper);
        return null != count && count > 0L;
    }

    Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper);

根据id查询

    T selectById(Serializable id);

根据id数组查询

    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

根据传入的实体类对象查询,只能等值查询:

    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

根据查询条件如果有的话且数量为1个则返回,没有返回

default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
        List<T> list = this.selectList(queryWrapper);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

根据自定义的查询条件分别输出数量和数据:

    Long selectCount(@Param("ew") Wrapper<T> queryWrapper);

    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);

查询特定字段的数据,并且返回:

 List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);

查询并且返回唯一的字段:

    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);

根据输入分页的,页码和每一页的大小以及相对应的条件返回数据;

<P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);

    <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper);

测试方法如下:

//selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有
//        1、查询全部
        List<User> userlist = userMapper.selectList(null);
        System.out.println(userlist);
//        2、根据id查询
        User user = userMapper.selectById(1);
        System.out.println(user);
//        3、根据ids查询
        List<Long> list = Arrays.asList(1L, 2L, 3L);
        List<User> users = userMapper.selectBatchIds(list);
//        4、根据条件查询全部字段
        Map<String,Object> map = new HashMap<>();
        map.put("name","张三");
        List<User> userCondation = userMapper.selectByMap(map);
        // 查询特定字段,返回 Map
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.select("name", "age")  // 只查询 name 和 age 字段
                .eq("age", 25);

        List<Map<String, Object>> mapList = userMapper.selectMaps(wrapper);
// 返回: List<Map>,每个Map的key是字段名,value是字段值
// 使用: mapList.get(0).get("name"), mapList.get(0).get("age")

// 生成的SQL: SELECT name, age FROM user WHERE age = 25
        System.out.println(mapList);
        QueryWrapper<User> wrapper1 = new QueryWrapper<>();
        wrapper.select("name")  // 查询 name 字段
                .eq("age", 25);

        List<Object> names = userMapper.selectObjs(wrapper);
// 返回: ["张三", "李四", "王五"] - 只有 name 字段的值
// 使用: String name = (String) names.get(0);

// 生成的SQL: SELECT name FROM user WHERE age = 25
//
    @Test
    public void testSelectPage() {
        System.out.println("=== selectPage 分页查询实体 ===");

        // 1. 创建分页对象
        Page<User> page = new Page<>(1, 10); // 第1页,每页10条

        // 2. 创建查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<>();

        // 3. 执行分页查询
        Page<User> result = userMapper.selectPage(page, wrapper);

        // 4. 处理结果
        System.out.println("总记录数: " + result.getTotal());
        System.out.println("总页数: " + result.getPages());
        System.out.println("当前页: " + result.getCurrent());
        System.out.println("每页大小: " + result.getSize());
        System.out.println("当前页数据: " + result.getRecords().size());

        // 遍历当前页数据
        result.getRecords().forEach(user -> {
            System.out.println("用户: " + user.getName() + ", 年龄: " + user.getAge());
        });
    }

    @Test
    public void testSelectPage() {
        System.out.println("=== selectPage 分页查询实体 ===");

        // 1. 创建分页对象
        Page<User> page = new Page<>(1, 10); // 第1页,每页10条

        // 2. 创建查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<>();

        // 3. 执行分页查询
        Page<User> result = userMapper.selectPage(page, wrapper);

        // 4. 处理结果
        System.out.println("总记录数: " + result.getTotal());
        System.out.println("总页数: " + result.getPages());
        System.out.println("当前页: " + result.getCurrent());
        System.out.println("每页大小: " + result.getSize());
        System.out.println("当前页数据: " + result.getRecords().size());

        // 遍历当前页数据
        result.getRecords().forEach(user -> {
            System.out.println("用户: " + user.getName() + ", 年龄: " + user.getAge());
        });
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值