一起来学Mybatis Plus(四) & Service CRUD接口

前言

目前正在出一个Mybatis Plus系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~

之前给大家讲过Mybatis教程,而MyBatis-Plus 是一个 MyBatis 的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。大家需要注意的是它只是一个工具,大家需要掌握和重点学习的依然是Mybatis,在熟练掌握基础的情况下使用MyBatis-Plus会达到事半功倍的效果。

好了, 废话不多说直接开整吧~

在第一节中给大家快速体验了一下基本的crud,本节带大家详细的介绍下内置的一些crud接口

Service & CRUD

细心的小伙伴可能发现在生成的UserService接口中继承了IService接口,该接口是由MyBatisPlus提供的,内置了诸多的crud方法,接下来一起看下如何使用

Save

java 复制代码
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);

下面一起测试一下:

java 复制代码
package com.springboot.all.mybatisplus.controller;

import com.springboot.all.mybatisplus.entity.User;
import com.springboot.all.mybatisplus.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;


@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/save")
    @ResponseBody
    public void saveUser() {
        User user = new User();
        user.setName("小明");
        user.setAge(18);
        user.setVersion(1);
        userService.save(user);

        User user1 = new User();
        user1.setName("小明1");
        user1.setAge(20);
        user1.setVersion(1);

        User user2 = new User();
        user2.setName("小明2");
        user2.setAge(21);
        user2.setVersion(1);
        List<User> userList = new ArrayList<>();
        userList.add(user1);
        userList.add(user2);
        userService.saveBatch(userList);
    }
}
  • Service类,内部无需实现直接使用IService提供的接口方法
java 复制代码
public interface UserService extends IService<User> {

}

运行测试下:

log 复制代码
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@58de5809] will not be managed by Spring
==>  Preparing: INSERT INTO sys_user ( name, age, version ) VALUES ( ?, ?, ? )
==> Parameters: 小明(String), 18(Integer), 1(Integer)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6911108f]
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@58de5809] will be managed by Spring
==>  Preparing: INSERT INTO sys_user ( name, age, version ) VALUES ( ?, ?, ? )
==> Parameters: 小明1(String), 20(Integer), 1(Integer)
==> Parameters: 小明2(String), 21(Integer), 1(Integer)

通过日志可以看到执行成功

Update

java 复制代码
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
  • Wrapper<T> updateWrapper 实体对象封装操作类 UpdateWrapper
  • T entity 实体对象
  • Collection<T> entityList 实体对象集合
  • int batchSize 更新批次数量

一起测试下:

java 复制代码
@GetMapping("/update")
@ResponseBody
public void updateUser() {
    User user = new User();
    user.setId(1731552348470849545L);
    user.setName("小明-UPDATE");
    userService.updateById(user);

    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    // 类似 where name = "小明1"
    updateWrapper.eq("name","小明1");
    User user1 = new User();
    user1.setName("小明1-UPDATE");
    userService.update(user1, updateWrapper);

}

结果:

log 复制代码
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3c78383f] will not be managed by Spring
==>  Preparing: UPDATE sys_user SET name=? WHERE id=?
==> Parameters: 小明-UPDATE(String), 1731552348470849545(Long)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@268f536b]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2e5fec60] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@3c78383f] will not be managed by Spring
==>  Preparing: UPDATE sys_user SET name=? WHERE (name = ?)
==> Parameters: 小明1-UPDATE(String), 小明1(String)
<==    Updates: 1

通用的大家在学习的过程中可以对照sql执行的情况来理解

SaveOrUpdate

java 复制代码
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

从字面意思也很好理解,有时候我们经常会有这种需求,比如我们需要在数据库中保存一条数据,如果存在就更新,如果不存在就插入一条数据。

  • T entity 实体对象
  • Wrapper updateWrapper实体对象封装操作类UpdateWrapper`
  • Collection<T> entityList 实体对象集合
  • int batchSize 插入批次数量

下面一起来测试下:

java 复制代码
@GetMapping("/saveOrUpdate")
@ResponseBody
public void saveOrUpdateUser() {
    User user = new User();
    user.setName("小明-saveOrUpdate");
    userService.saveOrUpdate(user);

    User user1 = new User();
    user1.setId(1731552348470849551L);
    user1.setName("小明2");
    userService.saveOrUpdate(user1);



}

结果:

log 复制代码
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@7f11356f] will be managed by Spring
==>  Preparing: SELECT id,name,age,version,create_at,update_at FROM sys_user WHERE id=?
==> Parameters: 1731552348470849551(Long)
<==    Columns: id, name, age, version, create_at, update_at
<==        Row: 1731552348470849551, 小明1, 0, null, 2023-12-19 10:14:34, 2023-12-19 10:14:34
<==      Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27ff4b17]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27ff4b17] from current transaction
==>  Preparing: UPDATE sys_user SET name=? WHERE id=?
==> Parameters: 小明2(String), 1731552348470849551(Long)
<==    Updates: 1

从结果来看第一条不存在所以进行了新增,第二条根据了存在所以进行了更新,我们可以看出在不指定条件的情况下根据ID主键来判断是否存在,如果存在就更新,不存在就插入一条数据。

有时候我们需要根据多个条件来判断是否存在,比如我们需要根据nameage来判断是否存在,那么我们就需要使用Wrapper来进行条件的封装操作。

java 复制代码
@GetMapping("/saveOrUpdate")
@ResponseBody
public void saveOrUpdateUser() {
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.eq("name","小明-saveOrUpdate");
    User user1 = new User();
    user1.setName("小明-saveOrUpdate1");
    userService.saveOrUpdate(user1, updateWrapper);
}

结果:

log 复制代码
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@386e3ce0] will not be managed by Spring
==>  Preparing: UPDATE sys_user SET name=? WHERE (name = ?)
==> Parameters: 小明-saveOrUpdate1(String), 小明-saveOrUpdate(String)
<==    Updates: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5977861]

结果发现,因为小明-saveOrUpdate这条数据存在,所以进行了更新

Remove

java 复制代码
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
  • Wrapper<T> queryWrapper 实体包装类 QueryWrapper
  • Serializable id 主键 ID
  • Map<String, Object> columnMap 表字段 map 对象
  • Collection<? extends Serializable> idList 主键 ID 列表
java 复制代码
@GetMapping("/remove")
@ResponseBody
public void remove() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("name","小明-saveOrUpdate1");
    userService.remove(queryWrapper);


    Map<String, Object> map = new HashMap<>();
    map.put("name", "小明2");
    userService.removeByMap(map);
}

结果:

log 复制代码
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@56a1ca2e] will not be managed by Spring
==>  Preparing: DELETE FROM sys_user WHERE (name = ?)
==> Parameters: 小明-saveOrUpdate1(String)
<==    Updates: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6661b17]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@71dec861] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@56a1ca2e] will not be managed by Spring
==>  Preparing: DELETE FROM sys_user WHERE (name = ?)
==> Parameters: 小明2(String)
<==    Updates: 2

Get & 查询单个记录

java 复制代码
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
  • Serializable id 主键 ID
  • Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper
  • boolean throwEx 有多个 result 是否抛出异常
  • T entity 实体对象
  • Function<? super Object, V> mapper 转换函数

List & 查询多条记录

java 复制代码
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
  • Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper
  • Collection<? extends Serializable> idList 主键 ID 列表
  • Map<String, Object> columnMap 表字段 map 对象
  • Function<? super Object, V> mapper 转换函数

Page & 分页查询

java 复制代码
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
  • IPage<T> page 翻页对象
  • Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper

Count & 查询总记录数

java 复制代码
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
  • Wrapper<T> queryWrapper 实体对象封装操作类 QueryWrapper

这里不一一给大家演示了,道理都是相通的,主要给大家说下分页数据怎么查,下面是一个根据条件查询分页的例子:

java 复制代码
@GetMapping("/page")
@ResponseBody
public Object page() {
    // 创建Page对象,指定当前页和每页显示的数据条数
    Page<User> page = new Page<>(1, 10);

    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name","%小明%");
    page = userService.page(page, queryWrapper);

    // 获取总记录数
    long size = page.getSize();
    long total = page.getTotal();
    long current = page.getCurrent();
    // 获取分页数据列表
    List<User> list = page.getRecords();

    JSONObject json = new JSONObject();
    json.put("size", size);
    json.put("total", total);
    json.put("current", current);
    json.put("list", list);
    return json;
}

结果:

log 复制代码
==>  Preparing: SELECT id,name,age,version,create_at,update_at FROM sys_user WHERE (name LIKE ?) LIMIT ?
==> Parameters: %%小明%%(String), 10(Long)
<==    Columns: id, name, age, version, create_at, update_at
<==        Row: 1731552348470849540, 小明, 18, null, 2023-12-19 09:37:57, 2023-12-19 09:37:57
<==        Row: 1731552348470849541, 小明, 18, 1, 2023-12-19 09:40:05, 2023-12-19 09:40:05
<==        Row: 1731552348470849542, 小明, 18, 1, 2023-12-19 09:54:55, 2023-12-19 09:54:55
<==        Row: 1731552348470849545, 小明-UPDATE, 18, 1, 2023-12-19 09:57:21, 2023-12-19 10:07:48
<==        Row: 1731552348470849546, 小明1-UPDATE, 20, 1, 2023-12-19 09:57:21, 2023-12-19 10:07:48
<==        Row: 1731552348470849549, 小明1, 0, null, 2023-12-19 10:13:55, 2023-12-19 10:13:55
<==      Total: 6
json 复制代码
{"total":6,"current":1,"size":10,"list":[{"name":"小明","updateAt":"2023-12-19T01:37:57.000+00:00","id":1731552348470849540,"age":18,"createAt":"2023-12-19T01:37:57.000+00:00"},{"name":"小明","updateAt":"2023-12-19T01:40:05.000+00:00","id":1731552348470849541,"version":1,"age":18,"createAt":"2023-12-19T01:40:05.000+00:00"},{"name":"小明","updateAt":"2023-12-19T01:54:55.000+00:00","id":1731552348470849542,"version":1,"age":18,"createAt":"2023-12-19T01:54:55.000+00:00"},{"name":"小明-UPDATE","updateAt":"2023-12-19T02:07:48.000+00:00","id":1731552348470849545,"version":1,"age":18,"createAt":"2023-12-19T01:57:21.000+00:00"},{"name":"小明1-UPDATE","updateAt":"2023-12-19T02:07:48.000+00:00","id":1731552348470849546,"version":1,"age":20,"createAt":"2023-12-19T01:57:21.000+00:00"},{"name":"小明1","updateAt":"2023-12-19T02:13:55.000+00:00","id":1731552348470849549,"age":0,"createAt":"2023-12-19T02:13:55.000+00:00"}]}

此外,还需要更改一下配置,添加mubatisplus分页插件

java 复制代码
@EnableTransactionManagement
@Configuration
@MapperScan("com.springboot.all.mybatisplus.mapper")
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 注册乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        // 注册分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

以上就是IService接口提供的crud方法,如果感兴趣的小伙伴可以看下源码

结束语

下节给大家讲解Mapper CRUD接口

本着把自己知道的都告诉大家,如果本文对有所帮助,点赞+关注鼓励一下呗~

MybatisPlus教程相关文章

往期Nginx教程相关文章

往期Docker教程相关文章

往前Shell脚本编程相关文章

往期Linux相关文章

往期面试题相关文章

项目源码(源码已更新 欢迎star⭐️)

往期设计模式相关文章

设计模式项目源码(源码已更新 欢迎star⭐️)

Kafka 专题学习

项目源码(源码已更新 欢迎star⭐️)

ElasticSearch 专题学习

项目源码(源码已更新 欢迎star⭐️)

往期并发编程内容推荐

推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

博客(阅读体验较佳)

相关推荐
张铁铁是个小胖子1 小时前
MyBatis学习
java·学习·mybatis
0zxm1 小时前
06 - Django 视图view
网络·后端·python·django
m0_748257181 小时前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端
小_太_阳2 小时前
Scala_【1】概述
开发语言·后端·scala·intellij-idea
智慧老师2 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
搬码后生仔4 小时前
asp.net core webapi项目中 在生产环境中 进不去swagger
chrome·后端·asp.net
凡人的AI工具箱4 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
Lx3525 小时前
Pandas数据重命名:列名与索引为标题
后端·python·pandas
小池先生5 小时前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
百罹鸟5 小时前
【vue高频面试题—场景篇】:实现一个实时更新的倒计时组件,如何确保倒计时在页面切换时能够正常暂停和恢复?
vue.js·后端·面试