前言
目前正在出一个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
主键来判断是否存在,如果存在就更新,不存在就插入一条数据。
有时候我们需要根据多个条件来判断是否存在,比如我们需要根据name
和age
来判断是否存在,那么我们就需要使用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
主键 IDMap<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
主键 IDWrapper<T> queryWrapper
实体对象封装操作类 QueryWrapperboolean 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
实体对象封装操作类 QueryWrapperCollection<? 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脚本编程相关文章
- 一起来学Shell脚本编程(一)
- 一起来学Shell脚本编程(二)
- 一起来学Shell脚本编程(三)
- 一起来学Shell脚本编程(四)
- 一起来学Shell脚本编程(五)
- 一起来学Shell脚本编程(六)
- 一起来学Shell脚本编程(七)
往期Linux相关文章
- 一起来学Linux命令(一)
- 一起来学Linux命令(二)
- 一起来学Linux命令(三)
- 一起来学Linux命令(四)
- 一起来学Linux命令(五)
- 一起来学Linux命令(六)
- 一起来学Linux命令(七)
- 一起来学Linux命令(八)
- 一起来学Linux命令(九)
- 一起来学Linux命令(十)
往期面试题相关文章
- 查漏补缺第一期(Redis相关)
- 查漏补缺第二期(synchronized & 锁升级)
- 查漏补缺第三期(分布式事务相关)
- 查漏补缺第四期(Mysql相关)
- 查漏补缺第五期(HashMap & ConcurrentHashMap)
- 查漏补缺第六期(京东一面)
- 查漏补缺第七期(美团到店一面)
- 查漏补缺第八期(阿里一面)
- 查漏补缺第九期(阿里二面)
- 查漏补缺第十期(网易实习一面)
- 查漏补缺第十一期(网易实习二面)
- 查漏补缺第十二期(网易实习三面)
- 查漏补缺第十三期(滴滴实习一面)
- 查漏补缺第十四期(滴滴实习二面)
- 查漏补缺第十五期(华为一面)
- 查漏补缺第十六期(华为二面)
- 查漏补缺第十七期(华为三面)
- 查漏补缺第十八期(你了解class文件吗)
项目源码(源码已更新 欢迎star⭐️)
往期设计模式相关文章
- 一起来学设计模式之认识设计模式
- 一起来学设计模式之单例模式
- 一起来学设计模式之工厂模式
- 一起来学设计模式之建造者模式
- 一起来学设计模式之原型模式
- 一起来学设计模式之适配器模式
- 一起来学设计模式之桥接模式
- 一起来学设计模式之组合模式
- 一起来学设计模式之装饰器模式
- 一起来学设计模式之外观模式
- 一起来学设计模式之享元模式
- 一起来学设计模式之代理模式
- 一起来学设计模式之责任链模式
- 一起来学设计模式之命令模式
- 一起来学设计模式之解释器模式
- 一起来学设计模式之迭代器模式
- 一起来学设计模式之中介者模式
- 一起来学设计模式之备忘录模式
- 一起来学设计模式之观察者模式
- 一起来学设计模式之状态模式
- 一起来学设计模式之策略模式
- 一起来学设计模式之模板方法模式
- 一起来学设计模式之访问者模式
- 一起来学设计模式之依赖注入模式
设计模式项目源码(源码已更新 欢迎star⭐️)
Kafka 专题学习
- 一起来学kafka之Kafka集群搭建
- 一起来学kafka之整合SpringBoot基本使用
- 一起来学kafka之整合SpringBoot深入使用(一)
- 一起来学kafka之整合SpringBoot深入使用(二)
- 一起来学kafka之整合SpringBoot深入使用(三)
项目源码(源码已更新 欢迎star⭐️)
ElasticSearch 专题学习
项目源码(源码已更新 欢迎star⭐️)
往期并发编程内容推荐
- Java多线程专题之线程与进程概述
- Java多线程专题之线程类和接口入门
- Java多线程专题之进阶学习Thread(含源码分析)
- Java多线程专题之Callable、Future与FutureTask(含源码分析)
- 面试官: 有了解过线程组和线程优先级吗
- 面试官: 说一下线程的生命周期过程
- 面试官: 说一下线程间的通信
- 面试官: 说一下Java的共享内存模型
- 面试官: 有了解过指令重排吗,什么是happens-before
- 面试官: 有了解过volatile关键字吗 说说看
- 面试官: 有了解过Synchronized吗 说说看
- Java多线程专题之Lock锁的使用
- 面试官: 有了解过ReentrantLock的底层实现吗?说说看
- 面试官: 有了解过CAS和原子操作吗?说说看
- Java多线程专题之线程池的基本使用
- 面试官: 有了解过线程池的工作原理吗?说说看
- 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看
- 面试官: 阻塞队列有了解过吗?说说看
- 面试官: 阻塞队列的底层实现有了解过吗? 说说看
- 面试官: 同步容器和并发容器有用过吗? 说说看
- 面试官: CopyOnWrite容器有了解过吗? 说说看
- 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析)
- 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析)
- 面试官: CountDownLatch有了解过吗?说说看(源码剖析)
- 面试官: CyclicBarrier有了解过吗?说说看(源码剖析)
- 面试官: Phaser有了解过吗?说说看
- 面试官: Fork/Join 有了解过吗?说说看(含源码分析)
- 面试官: Stream并行流有了解过吗?说说看