MybatisPlus入门教程及实现基础的增删改查

此篇博客主要针对于有开发基础的朋友学习~

首先提几个问题:
1、什么是Mybatis?
2、什么是MybatisPlus?
3、Mybatis和MybatisPlus又有什么区别呢?

问题1:Mybatis是一个持久层的框架,我们通过配置mapper.xml的方式来自定义sql,在xml中,mybatis给我们提供了很多标签,比如:
<resultMap>用来映射数据库字段和实体类属性之间的对应关系
<select>标签用来定义一个select查询方法
<where>标签用来构建where条件
<if>标签用来定义一个条件判断等等。

Mybaits的优点也很明显:
1、我们可以自定义任何sql语句来实现我们的业务,也就是说sql我们可以想怎么写怎么写,想怎么查怎么查。
2、实现了sql语句和java代码解耦。

问题2:MybatisPlus属于Mybatis的一个增强版本,对于Mybatis来说我们要想简单实现一个增删改查,还是要在mapper.xml中编写sql来实现。但是对于MybatisPlus来说它已经为我们封装好了很多crud的接口供我们调用,如果只是简单地增删改查我们完全不用再在mapper.xml中编写sql了,一行代码就搞定。

问题3:区别的话问题2中已经说了一部分,对于Mybatis来说我们还是要基于编写sql来实现业务,这也就意味着如果项目中要从mysql数据库换成oralce数据库会是一件很麻烦的事情,很多sql语句都要修改。但是对于MybatisPlus来说很多业务我们不需要写sql而是调一个接口就能搞定,这里就方便了很多。

下面我们就来学习一下MybatisPlus的相关知识:

一、引入依赖

首先我们先构建一个简单的springboot项目,并在pom文件中加入MybatisPlus的依赖:

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

二、建表

我们在数据库中建一张表:

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `student_name` varchar(30) DEFAULT '' COMMENT '学生姓名',
  `student_num` varchar(30) DEFAULT '' COMMENT '学号',
  `address` varchar(500) DEFAULT '' COMMENT '家庭住址',
  `student_age` int(3) DEFAULT NULL COMMENT '年龄',
  `student_sex` char(1) DEFAULT '0' COMMENT '性别(0男 1女 2未知)',
  `student_birthday` datetime DEFAULT NULL COMMENT '生日',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='学生表';

三、创建实体类

建完之后我们就在项目中建我们的Student实体类:

package com.citc.develop.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.util.Date;

/**
 * 学生对象 student
 * 
 * @author szq
 * @date 2021-02-22
 */
@Data
public class Student
{
    private static final long serialVersionUID = 1L;

    /** 主键id */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /** 学生名称 */
    private String studentName;

    /** 学号 */
    private String studentNum;

    /** 家庭住址 */
    private String address;

    /** 年龄 */
    private Integer studentAge;

    /** 性别(0男 1女 2未知) */
    private String studentSex;

    /** 生日 */
    private Date studentBirthday;

}

这里有一个细节分享一下,id字段有一个@TableId注解,这个注解标明了这个字段是id主键并指定了id生成策略为数据库id自增,也就是说我们在插入的时候不需要给id属性set值。
我们点进去这个AUTO可以发现mybatisplus现支持五种id生成策略(3.3.0版本之后):

在这里插入图片描述

四、创建Mapper

package com.citc.develop.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.citc.develop.entity.Student;
import org.apache.ibatis.annotations.Mapper;


/**
 * @author szq
 * @since 2021-12-14
 */
@Mapper
public interface StudentMapper extends BaseMapper<Student> {

}

五、创建Service接口

package com.citc.develop.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.citc.develop.entity.Student;

/**
 *
 * @author szq
 * @since 2021-12-14
 */
public interface StudentService extends IService<Student> {

}

六、创建相应的Service实现

package com.citc.develop.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.citc.develop.dao.StudentMapper;
import com.citc.develop.entity.Student;
import com.citc.develop.service.StudentService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

/**
 *
 * @author szq
 * @since 2021-12-14
 */
@Service
@AllArgsConstructor
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {

}

其实写到这里最基础的增删改查已经实现了,只要我们的mapper接口继承了BaseMapper就已经能进行crud了,并且这个接口中封装了很多常用的查询方法。
在这里插入图片描述

下面我们写一个简单的接口来试验一下:

首先我先配置一下application.yml打印一下sql日志

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

然后我们编写StudentApi

package com.citc.develop.api;

import com.citc.develop.dto.StudentDto;
import com.citc.develop.service.StudentService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

/**
 * @author szq
 * @Description
 * @date Created in 2022/3/1
 */
@RestController
@RequestMapping("/api/v1/student")
@AllArgsConstructor
public class StudentApi {

    private final StudentService studentService;

    @PostMapping("/add")
    public Long add(StudentDto studentDto) {
        return studentService.save(studentDto);
    }
}

然后在service实现类里,我简单的做了一个对象的copy,并返回了记录的id:

package com.citc.develop.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.citc.develop.dao.StudentMapper;
import com.citc.develop.dto.StudentDto;
import com.citc.develop.entity.Student;
import com.citc.develop.service.StudentService;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

/**
 *
 * @author szq
 * @since 2021-12-14
 */
@Service
@AllArgsConstructor
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {

    @Override
    public Long save(StudentDto studentDto) {
        Student student = new Student();
        BeanUtils.copyProperties(studentDto,student);
        this.save(student);
        return student.getId();
    }
}

下面我们启动一下项目,打开postman传入参数点击send:
在这里插入图片描述
看返回结果已经成功了,我们来看一下控制台打印的sql:
在这里插入图片描述
然后看一下表中的数据:
在这里插入图片描述
记录已经成功插入,至此我们已经实现了“增”的功能。

下面我们来看一下删除功能

删除功能更简单,前端只需要传递一个记录id,然后在调用一下service的remove接口即可,下面我把控制器层的代码贴出来:

@GetMapping("/delete")
    public boolean delete(Long id) {
        return studentService.removeById(id);
}

用postman调用一下:
在这里插入图片描述

好了,删除功能已经实现了,但是在我们实际业务中,很多场景都是需要逻辑删除的,这个mybatis-plus也已经有相关的注解实现下面我们来看一下:

@TableLogic

就是这个注解,我们只需要在表里新加一个删除标记的字段,例如我在student表里加一个delete_flag字段,0表示没有删除,1表示已经删除,
然后在我们实体类中也加上这个字段:
在这里插入图片描述
这样就已经实现逻辑删除了,下面我们再调用一下刚才的删除接口会发现,日志里已经不走delete语句而是update语句了:
在这里插入图片描述
0表示没有删除,1表示已经删除,这是mybatisplus默认的映射关系,如果你想用0表示已经删除,1标识没有删除,那么我们注解可以这么写:
在这里插入图片描述
那么在实际项目中,我们又有很多张表,每张表可能都有delete_flag字段,那么在每个实体类中都加这一行代码多少有点冗余,有没有更简单的配置方式?
答案当然是有的,我们可以通过yml配置的方式来实现逻辑删除:
在这里插入图片描述
这样的实现方式是和上面一样的,我们就不需要把每个表对应的实体类都通过加注解来实现逻辑删除了,一个配置就能搞定所有表的逻辑删除,但是前提条件是这些表的逻辑删除字段都得是一样的,如果说有的表不一样,那我们就还是通过注解方式来实现,注解的实现方式是比配置文件的的优先级高,在两种都配置的情况下,mybatisplus会优先执行注解的配置。

好了,下面我们来看mybatisplus的更新:

mybatisplus的更新和查询都是通过条件构造器来实现的,这个条件构造器也很好理解,就是sql语句中的where后的语句,下面我们来看一下:
这里先插入几条数据

INSERT INTO `student` VALUES (2, '张三', '1231231', '河南省郑州市', 20, '0', '1995-09-08 09:27:18', NULL, '0');
INSERT INTO `student` VALUES (3, '李四', '22222', '山东省青岛市', 22, '0', '1995-09-08 09:27:18', NULL, '0');
INSERT INTO `student` VALUES (4, '张无忌', '444122', '河南省信阳市', 22, '0', '1995-09-08 09:27:18', NULL, '0');
INSERT INTO `student` VALUES (5, '大朗', '53431', '山东省烟台市', 22, '0', '1995-09-08 09:27:18', NULL, '0');
INSERT INTO `student` VALUES (6, '嘿嘿嘿', '855654', '北京市', 22, '0', '1995-09-08 09:27:18', NULL, '0');
INSERT INTO `student` VALUES (7, '里无数', '7544556', '四川省成都市', 22, '0', '1995-09-08 09:27:18', NULL, '0');
INSERT INTO `student` VALUES (8, '李武', '9984554', '河南省驻马店市', 22, '0', '1995-09-08 09:27:18', NULL, '0');

通常在项目中我们更新的接口前端会传来一个带有id字段的dto,我们直接根据id更新记录就好了:
在这里插入图片描述

但是这里有一个问题需要注意一下,mybatisplus只会更新改变了的字段,比如说前端传的dto中只有address这一个字段的值,那么mybatisplus就只会更新这一个字段,其他字段的值不变,如果我们想把某一条记录中的一两个字段从非null更新成null,那我们需要手动将实体类中对应的属性set成null。

上面我们说的是根据id做整体更新,那么如果我们想自定义条件来更新呢?
mybatisplus给我们提供了UpdateWrapper条件构造器,我们来看一下如何使用:

这是现在表里的数据:
在这里插入图片描述
比如说我现在想更新所有年龄是22岁的学生的性别,从0更新成1,那么我们可以这么来写条件构造器:

在这里插入图片描述
我们来看一下打印出来的sql:
在这里插入图片描述
下面是条件构造器的常用方法:

eq(R column, Object val); // 等价于 =,例: eq("name", "老王") ---> name = '老王'
ne(R column, Object val); // 等价于 <>,例: ne("name", "老王") ---> name <> '老王'
gt(R column, Object val); // 等价于 >,例: gt("age", 18) ---> age > 18
ge(R column, Object val); // 等价于 >=,例: ge("age", 18) ---> age >= 18
lt(R column, Object val); // 等价于 <,例: lt("age", 18) ---> age < 18
le(R column, Object val); // 等价于 <=,例: le("age", 18) ---> age <= 18
between(R column, Object val1, Object val2); // 等价于 between a and b, 例: between("age", 18, 30) ---> age between 18 and 30
notBetween(R column, Object val1, Object val2); // 等价于 not between a and b, 例: notBetween("age", 18, 30) ---> age not between 18 and 30
in(R column, Object... values); // 等价于 字段 IN (v0, v1, ...),例: in("age",1,2,3) ---> age in (1,2,3)
notIn(R column, Object... values); // 等价于 字段 NOT IN (v0, v1, ...), 例: notIn("age",1,2,3) ---> age not in (1,2,3)
inSql(R column, Object... values); // 等价于 字段 IN (sql 语句), 例: inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3)
notInSql(R column, Object... values); // 等价于 字段 NOT IN (sql 语句), 例: notInSql("id", "select id from table where id < 3") ---> id not in (select id from table where id < 3)
like(R column, Object val); // 等价于 LIKE '%值%',例: like("name", "王") ---> name like '%王%'
notLike(R column, Object val); // 等价于 NOT LIKE '%值%',例: notLike("name", "王") ---> name not like '%王%'
likeLeft(R column, Object val); // 等价于 LIKE '%值',例: likeLeft("name", "王") ---> name like '%王'
likeRight(R column, Object val); // 等价于 LIKE '值%',例: likeRight("name", "王") ---> name like '王%'
isNull(R column); // 等价于 IS NULL,例: isNull("name") ---> name is null
isNotNull(R column); // 等价于 IS NOT NULL,例: isNotNull("name") ---> name is not null
groupBy(R... columns); // 等价于 GROUP BY 字段, ..., 例: groupBy("id", "name") ---> group by id,name
orderByAsc(R... columns); // 等价于 ORDER BY 字段, ... ASC, 例: orderByAsc("id", "name") ---> order by id ASC,name ASC
orderByDesc(R... columns); // 等价于 ORDER BY 字段, ... DESC, 例: orderByDesc("id", "name") ---> order by id DESC,name DESC
having(String sqlHaving, Object... params); // 等价于 HAVING ( sql语句 ), 例: having("sum(age) > {0}", 11) ---> having sum(age) > 11
or(); // 等价于 a or b, 例:eq("id",1).or().eq("name","老王") ---> id = 1 or name = '老王'
or(Consumer<Param> consumer); // 等价于 or(a or/and b),or 嵌套。例: or(i -> i.eq("name", "李白").ne("status", "活着")) ---> or (name = '李白' and status <> '活着')
and(Consumer<Param> consumer); // 等价于 and(a or/and b),and 嵌套。例: and(i -> i.eq("name", "李白").ne("status", "活着")) ---> and (name = '李白' and status <> '活着')
nested(Consumer<Param> consumer); // 等价于 (a or/and b),普通嵌套。例: nested(i -> i.eq("name", "李白").ne("status", "活着")) ---> (name = '李白' and status <> '活着')
apply(String applySql, Object... params); // 拼接sql(若不使用 params 参数,可能存在 sql 注入),例: apply("date_format(dateColumn,'%Y-%m-%d') = {0}", "2008-08-08") ---> date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")
last(String lastSql); // 无视优化规则直接拼接到 sql 的最后,可能存若在 sql 注入。
exists(String existsSql); // 拼接 exists 语句。例: exists("select id from table where age = 1") ---> exists (select id from table where age = 1)

这些条件构造同样的适用于在构造查询条件中,更新时我们获取的是UpdateWrapper而在查询时我们获取的是QueryWrapper,下面是表中现有的数据:

最简单的我们想根据主键id查询一条记录我们可以这么写:

Student student = this.getBaseMapper().selectById(2);

在这里插入图片描述

比如说现在想要查询年龄大于20岁的学生记录,那么我们可以这么写:

    private void customCondition(){
        // 通过Wrappers获取一个更新的条件构造器
        QueryWrapper<Student> queryWrapper = Wrappers.query();

        queryWrapper.gt("student_age",20);
		// 符合条件的学生记录
        List<Student> studentList = this.list(queryWrapper);

    }

这样记录就被我们查询出来了:
在这里插入图片描述
剩下的方法大家可以自己试一试。
希望我的文章能够帮助到大家,有问题请指出谢谢您。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/896365.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 外设驱动 应用 2 KEY 按键实验

2 按键 2.1 按键介绍 按键是指轻触式按键开关&#xff0c;也称之为轻触开关。按键开关是一种电子开关&#xff0c;属于电子元器件类&#xff0c;最早出现在日本&#xff0c;称之为&#xff1a;敏感型开关&#xff0c;使用时以满足操作力的条件向开关操作方向施压开关功能闭合…

RabbitMQ系列学习笔记(三)--工作队列模式

文章目录 一、工作队列模式原理二、工作队列模式实战1、抽取工具类2、消费者代码3、生产者代码4、查看运行结果 本文参考 尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件rabbitmq RabbitMQ 详解 Centos7环境安装Erlang、RabbitMQ详细过程(配图) 一、工作队列模式原理 与简单模式相…

MySQL中查询语句的执行流程

文章目录 前言流程图概述最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;今天我们一起探讨一下执行一条查询的SQL语句在MySQL内部都发生了什么&#xff0c;让你对MySQL内部的架构具备一个宏观上的了解 流程图 概述 对于查询语句的SQL的执行流程&#xff0c;主要可以分为…

架构师备考-背诵精华(系统架构评估)

系统架构评估是在对架构分析、评估的基础上&#xff0c;对架构策略的选取进行决策。它利用数学或逻辑分析技术&#xff0c;针对系统的一致性、正确性、质量属性、规划结果等不同方面&#xff0c;提供描述性、预测性和指令性的分析结果。 重要概念 敏感点&#xff1a;敏感点是…

信息学奥赛复赛复习18-CSP-J2022-01解密-二分答案、二分找边界、二分时间复杂度、二分求最小

PDF文档回复:20241017 1 P8814 [CSP-J 2022] 解密 [题目描述] 给定一个正整数 k&#xff0c;有 k 次询问&#xff0c;每次给定三个正整数 ni,ei,di&#xff0c;求两个正整数 pi,qi&#xff0c;使 nipiqi、eidi(pi−1)(qi−1)1 [输入格式] 第一行一个正整数 k&#xff0c;表…

单神经元建模:基于电导的模型[神经元结构、静息电位和等效电路]

文章目录 神经元结构、静息电位和等效电路神经元结构静息电位能斯特方程1. **描述浓度比的非线性关系**&#xff1a;2. **化学势与电势的关系**&#xff1a;3. **对称性**&#xff1a;4. **热力学与平衡**&#xff1a;总结&#xff1a; GHK方程Nernst方程和GHK方程的对比 等效电…

自动化检查网页的TDK,python+selenium自动化测试web的网页源代码中的title,Description,Keywords

首先&#xff0c;TDK是什么&#xff1f;对于新手小白来说&#xff0c;可能是懵逼的&#xff0c;所以这里给出一个官方的解说‌网页的TDK是指标题&#xff08;Title&#xff09;、描述&#xff08;Description&#xff09;和关键词&#xff08;Keywords&#xff09;的集合‌。这…

vue3播放m3u8格式hls监控流

1. 摄像头的hls监控流不同于普通m3u8的视频&#xff0c;video标签&#xff0c;iframe&#xff0c;videojs&#xff0c;vue-video-player无法解析 2. 解决办法 更换LivePlayer插件 官网https://www.liveqing.com/docs/manuals/LivePlayer.html#%E5%B1%9E%E6%80%A7-property 3…

Java项目-基于Springboot的招生管理系统项目(源码+说明).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Tkinter -- python GUI学习与使用

前言 python GUI 目前pythonGUI有很多&#xff0c;哪一个最好&#xff1f; 先说说我选择的思路&#xff0c;我的目的是开发一个易用的软件&#xff0c;最重要的是稳定&#xff0c;并且碰到问题能够解决&#xff0c;因此&#xff0c;我的目标很明确&#xff0c;有比较大的用户群…

cefsharp79.1.360(Chromium 79.0.3945.130)支持H264视频播放-PDF预览 老版本回顾系列体验

一、关于此版本 版本:Cef 79.1.36/CefSharp 79.1.360/Chromium 79.0.3945.130/支持H264/支持PDF预览 支持PDF预览和H264推荐版本 63/79/84/88/100/111/125 运行环境需要 visual c++ 2015不支持xp/vista/2003/2008默认不支持h264(版权问题)支持打印预览 print preview已知问题…

【计算机网络原理】GBN,SR,TCP区别以及案例介绍

概念介绍 GBN、SR和TCP协议的主要区别在于它们的重传机制、确认方式以及缓存机制的不同。‌ GBN&#xff08;Go-Back-N&#xff09;协议在数据传输中&#xff0c;如果某个报文段没有被正确接收&#xff0c;那么从这个报文段到后面的所有报文段都需要重新发送。GBN采用累计应答…

UI自动化测试 —— web端元素获取元素等待实践!

前言 Web UI自动化测试是一种软件测试方法&#xff0c;通过模拟用户行为&#xff0c;自动执行Web界面的各种操作&#xff0c;并验证操作结果是否符合预期&#xff0c;从而提高测试效率和准确性。 目的&#xff1a; 确保Web应用程序的界面在不同环境(如不同浏览器、操作系统)下…

每日OJ题_牛客_[NOIP2001]装箱问题_01背包_C++_Java

目录 牛客_[NOIP2001]装箱问题_01背包 题目解析 C代码 Java代码 牛客_[NOIP2001]装箱问题_01背包 [NOIP2001]装箱问题 (nowcoder.com) 描述&#xff1a; 有一个箱子容量为V&#xff08;正整数&#xff0c;0 ≤ V ≤ 20000&#xff09;&#xff0c;同时有n个物品&…

面向对象进阶(上)(JAVA笔记第二十二期)

p.s.这是萌新自己自学总结的笔记&#xff0c;如果想学习得更透彻的话还是请去看大佬的讲解 目录 static修饰符静态变量静态方法 工具类工具类的使用例子第一题第二题 static注意事项继承关系建立继承关系的格式继承的好处及使用场景继承的特点继承体系的设计继承中类的三大要素…

redis集群介绍

Redis集群是一种分布式存储系统&#xff0c;它通过将数据分散存储在多个Redis节点上来实现可扩展性和高可用性。每个节点都是一个独立的Redis服务器实例&#xff0c;它们通过网络相互连接&#xff0c;共同协作以提供数据服务。 在Redis集群中&#xff0c;数据被划分为多个槽&am…

巧用这4款免费视频剪辑软件,帮你释放无限的创意。

可以免费使用的视频剪辑软件对于普通创作者而言还是比较重要的。因为越来越多的人渴望通过视频来表达自己的创意、分享生活点滴以及传达各种信息。专业的软件价格贵&#xff0c;操作复杂。简单免费的工具才是大多数人的选择&#xff0c;所以我要给大家介绍几个好用且免费的剪辑…

3D Slicer 教程三 ---- 坐标系

上篇提到3D Slicer 教程二 ---- 数据集-CSDN博客 3d slicer的坐标系与大多数医学影像软件使用LPS&#xff08;左、后、上&#xff09;坐标系统不太一样, 今天就仔细介绍一下坐标系的区别,复盘一下在影像处理中遇到的坐标问题(集中在坐标处理相关的,图像插值,图像处理, 定位线,翻…

服务器软件之Tomcat

服务器软件之Tomcat 服务器软件之Tomcat 服务器软件之Tomcat一、什么是Tomcat二、安装Tomcat1、前提&#xff1a;2、下载3、解压下载的tomcat4、tomcat启动常见错误4.1、tomcat8.0 startup报错java.util.logging.ErrorManager: 44.2、java.lang.UnsatisfiedLinkError 三、Tomca…

Ansible概述

目录 一、ansible简介 二、absible的特点 三、ansible的工作原理以及流程 四、ansible环境安装部署 五、ansible命令行模块 六、inventory 主机清单 一、ansible简介 Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。…