前言
目前正在出一个Mybatis Plus
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
之前给大家讲过Mybatis
教程,而MyBatis-Plus
是一个 MyBatis
的增强工具,在MyBatis
的基础上只做增强不做改变,为简化开发、提高效率而生。大家需要注意的是它只是一个工具,大家需要掌握和重点学习的依然是Mybatis
,在熟练掌握基础的情况下使用MyBatis-Plus
会达到事半功倍的效果。
好了, 废话不多说直接开整吧~
在第一节中给大家快速体验了一下基本的crud
,本节带大家详细的介绍下内置的一些crud
接口
Service & CRUD
细心的小伙伴可能发现在生成的UserService
接口中继承了IService
接口,该接口是由MyBatisPlus
提供的,内置了诸多的crud
方法,接下来一起看下如何使用
Save
// 插入一条记录(选择字段,策略插入) boolean save(T entity); // 插入(批量) boolean saveBatch(Collection<T> entityList); // 插入(批量) boolean saveBatch(Collection<T> entityList, int batchSize);
下面一起测试一下:
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
提供的接口方法
public interface UserService extends IService<User> { }
运行测试下:
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
// 根据 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
更新批次数量
一起测试下:
@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); }
结果:
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
// 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
插入批次数量
下面一起来测试下:
@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); }
结果:
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
来进行条件的封装操作。
@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); }
结果:
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
// 根据 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 列表
@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); }
结果:
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 & 查询单个记录
// 根据 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 & 查询多条记录
// 查询所有 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 & 分页查询
// 无条件分页查询 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 & 查询总记录数
// 查询总记录数 int count(); // 根据 Wrapper 条件,查询总记录数 int count(Wrapper<T> queryWrapper);
Wrapper<T> queryWrapper
实体对象封装操作类 QueryWrapper
这里不一一给大家演示了,道理都是相通的,主要给大家说下分页数据怎么查,下面是一个根据条件查询分页的例子:
@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; }
结果:
==> 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
{"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
分页插件
@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
接口
本着把自己知道的都告诉大家,如果本文对有所帮助,点赞+关注
鼓励一下呗~