MyBatis-Plus(Ⅲ)IService详解
目录
一、逐一演示
1.save(插入一条)
结果
断言(引入概念)
2.saveBatch(批量插入)
结果
3.saveOrUpdateBatch(批量插入&更新)
结果
4.removeById(通过id删除)
结果
5.removeByMap(通过集合里的信息删除)
结果
6.remove(通过条件删除)
解析
结果
7.removeByIds(通过id批量删除)
结果
8.updateById(通过id修改)
结果
9.update(通过条件修改)
结果
10.updateBatchById(根据id批量更新)
结果
11.saveOrUpdate(插入或修改)
结果
12.getById(通过id查找)
结果
13.listByIds(查找多个id)
结果
14.listByMap(通过集合信息查找)
结果
15. getOne(判断获得是不是一条数据)
结果
16.getMap(返回一条数据的内容)
结果
17.count(返回数量)
结果
加上判断
结果
编辑 18. list(查找所有对象)
结果
加入条件
结果
19.page(分页)
结果
20.listMaps(获取所有数据)
结果
list和listMaps的区别
21.listObjs(获取某字段-不指定默认是主键id)
结果
QueryWrapper
22.其他
二、源码展示
在前面两篇文章中已经对MyBatis-Plus有关Dao层的封装文件BaseMapper,这篇文章就它封装的service层IService进行解读和使用演示。
一、逐一演示
上面在源码上简单标注了一下每段代码功能,现在test中测试一下每段的具体使用和展示结果,这里测试用的数据库信息仍旧是MyBatis-Plus详解Ⅰ(请点击查看)里的数据信息。
1.save(插入一条)
/*** 测试插入单个实体对象* 验证:插入成功后返回 true,并且实体对象的主键不为 null*/@Testpublic void testSave() {User user = new User();user.setName("张三");user.setAge(20);boolean result = userService.save(user);
// assertTrue(result); //断言
// assertNotNull(user.getId());System.out.println(result);}
结果

断言(引入概念)
一般来说,在代码中插入断言语句,可以用来检查程序运行时的某些条件是否为真。如果条件为真,则程序继续运行;如果条件为假,则会抛出
AssertionError
异常。当然在这里用到的并不是Java内置的断言机制,而是用的Assertions,即测试断言。
方法名称 用法 assertEquals
检查两个值是否相等 assertNotEquals
检查两个值是否不相等 assertTrue
检查某个条件是否为 true
assertFalse
检查某个条件是否为 false
assertNull
检查某个对象是否为 null
assertNotNull
检查某个对象是否不为 null
assertThrows
检查某个代码块是否抛出预期的异常 assertDoesNotThrow
检查某个代码块是否不抛出异常 assertArrayEquals
检查两个数组是否相等 assertSame
检查两个对象是否是同一个实例 assertNotSame
检查两个对象是否不是同一个实例 fail
强制测试失败 上面这些方法同样遵循:如果条件不符合预期,方法会抛出一个
AssertionError
(或其他具体的异常类型),导致测试失败。
为了代码可以顺利执行,我这里把断言注释掉了,用工作台的打印查看结果,下面同理。(一目了然,而且看起来也比较赏心悦目)
2.saveBatch(批量插入)
/*** 测试批量插入实体对象* 验证:批量插入成功后返回 true*/@Testpublic void testSaveBatch() {List<User> users = new ArrayList<>();User user1 = new User();user1.setName("李四");user1.setAge(22);User user2 = new User();user2.setName("王五");user2.setAge(23);users.add(user1);users.add(user2);boolean result = userService.saveBatch(users);System.out.println(result);}
结果
3.saveOrUpdateBatch(批量插入&更新)
即存在定义的id值则是修改数据信息,不存在则是插入
/*** 测试批量插入或更新实体对象* 验证:批量插入或更新成功后返回 true*/@Testpublic void testSaveOrUpdateBatch() {List<User> users = new ArrayList<>();User user1 = new User();user1.setName("赵六");user1.setAge(24);User user2 = new User();user2.setId(1L); // 假设数据库中已存在id为1的用户user2.setName("更新后的名字");user2.setAge(25);users.add(user1);users.add(user2);boolean result = userService.saveOrUpdateBatch(users);System.out.println(result);}
结果
4.removeById(通过id删除)
/*** 测试根据主键id删除实体对象* 验证:删除成功后返回 true*/@Testpublic void testRemoveById() {Long id = 1L; // 假设数据库中存在id为1的用户boolean result = userService.removeById(id);System.out.println(result);}
结果
注:这里返回false也无伤大雅,说明我的数据库中没有id是1的数据了(如果我用的是断言,那么这里就会报红色,代表测试不通过,所以我只用打印一下就知道我这里false是因为没有这一条数据而不报红)
5.removeByMap(通过集合里的信息删除)
/*** 测试根据字段值删除实体对象* 验证:删除成功后返回 true*/@Testpublic void testRemoveByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("name", "张三");columnMap.put("age", 20);boolean result = userService.removeByMap(columnMap);System.out.println(result);}
这里表示代码要找到我的数据库中一条name叫张三,同时龄是20岁的数据进行删除。
结果

6.remove(通过条件删除)
/*** 测试根据条件删除实体对象* 验证:删除成功后返回 true*/@Testpublic void testRemove() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name", "李四").eq("age", 22);boolean result = userService.remove(queryWrapper);System.out.println(result);}
解析
QueryWrapper
是 MyBatis-Plus 提供的一个条件构造器,用于构建 SQL 查询条件;它会将这些条件翻译为 SQL 的WHERE
子句,即:WHERE name = '李四' AND age = 22;
结果
7.removeByIds(通过id批量删除)
/*** 测试根据主键列表批量删除实体对象* 验证:删除成功后返回 true*/@Testpublic void testRemoveByIds() {List<Long> ids = Arrays.asList(1L, 2L); // 假设数据库中存在id为1和2的用户boolean result = userService.removeByIds(ids);System.out.println(result);}
结果

8.updateById(通过id修改)
/*** 测试根据主键更新实体对象* 验证:更新成功后返回 true*/@Testpublic void testUpdateById() {User user = new User();user.setId(1L); // 假设数据库中存在id为1的用户user.setName("更新后的名字");user.setAge(26);boolean result = userService.updateById(user);System.out.println(result);}
结果

9.update(通过条件修改)
/*** 测试根据条件更新实体对象* 验证:更新成功后返回 true*/@Testpublic void testUpdate() {UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("name", "张三").set("age", 27);boolean result = userService.update(updateWrapper);System.out.println(result);}
结果

10.updateBatchById(根据id批量更新)
/*** 测试批量更新实体对象* 验证:批量更新成功后返回 true*/@Testpublic void testUpdateBatchById() {List<User> users = new ArrayList<>();User user1 = new User();user1.setId(1L); // 假设数据库中存在id为1的用户user1.setName("更新后的名字1");user1.setAge(28);User user2 = new User();user2.setId(2L); // 假设数据库中存在id为2的用户user2.setName("更新后的名字2");user2.setAge(29);users.add(user1);users.add(user2);boolean result = userService.updateBatchById(users);System.out.println(result);}
结果
11.saveOrUpdate(插入或修改)
/*** 测试插入或更新单个实体对象* 验证:插入或更新成功后返回 true*/@Testpublic void testSaveOrUpdate() {User user = new User();user.setId(1L); // 假设数据库中存在id为1的用户user.setName("更新后的名字");user.setAge(30);boolean result = userService.saveOrUpdate(user);System.out.println(result);}
存在则修改,不存在则插入。
结果
12.getById(通过id查找)
/*** 测试根据主键获取实体对象* 验证:获取成功后返回的实体对象不为 null*/@Testpublic void testGetById() {Long id = 1L; // 假设数据库中存在id为1的用户User user = userService.getById(id);System.out.println(user);System.out.println(user.getName());}
结果
13.listByIds(查找多个id)
/*** 测试根据主键列表批量获取实体对象* 验证:返回的实体对象列表不为 null,且大小与主键列表一致*/@Testpublic void testListByIds() {List<Long> ids = Arrays.asList(1L, 2L); // 假设数据库中存在id为1和2的用户List<User> users = userService.listByIds(ids);System.out.println(users);System.out.println(users.size());}
结果
14.listByMap(通过集合信息查找)
/*** 测试根据字段值获取实体对象列表* 验证:返回的实体对象列表不为 null,且所有对象的字段值符合条件*/@Testpublic void testListByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("age", 20);List<User> users = userService.listByMap(columnMap);System.out.println(users);}
结果
15. getOne(判断获得是不是一条数据)
/*** 测试根据条件获取单个实体对象* 验证:获取成功后返回的实体对象不为 null*/@Testpublic void testGetOne() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name", "张三");User user = userService.getOne(queryWrapper);System.out.println(user);}
结果

①如果查询结果 恰好有一个 符合条件的记录,
getOne
会返回这个记录对应的实体对象。②如果查询结果 没有符合条件的记录,
getOne
的行为取决于是否启用异常抛出(由throwEx
参数决定):
如果
throwEx
为true
,会抛出异常(通常是NullPointerException
或类似的异常)。如果
throwEx
为false
,返回null
。③如果查询结果 多于一个 符合条件的记录,
getOne
会抛出异常(通常是TooManyResultsException
或类似的异常),因为它的预期是查询结果 最多只有一个。
16.getMap(返回一条数据的内容)
/*** 测试根据条件获取单个字段值(只能是一条数据,否则就报错)* 验证:获取成功后返回的字段值不为 null*/@Testpublic void testGetMap() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("name", "张三");Map<String, Object> map = userService.getMap(queryWrapper);System.out.println(map);}
结果
17.count(返回数量)
/*** 测试统计实体对象数量* 验证:返回的数量大于等于 0*/@Testpublic void testCount() {long count = userService.count();assertTrue(count >= 0);System.out.println(count);}
结果
加上判断
/*** 测试根据条件统计实体对象数量* 验证:返回的数量大于等于 0*/@Testpublic void testCountWithQueryWrapper() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age", 20);long count = userService.count(queryWrapper);assertTrue(count >= 0);System.out.println(count);}
结果
18. list(查找所有对象)
/*** 获取实体对象列表* 验证:返回的实体对象列表不为 null*/@Testpublic void testList() {List<User> users = userService.list();assertNotNull(users);System.out.println(users);}
结果
加入条件
查询结果不为
null
:确保查询返回的用户列表不为null
。所有用户的
age
字段不为null
:确保查询结果中的每个用户对象的age
字段都有值(即不为null
)
/*** 测试根据条件获取实体对象列表* 验证:返回的实体对象列表不为 null,且所有对象符合条件*/@Testpublic void testListWithQueryWrapper() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByAsc("age");List<User> users = userService.list(queryWrapper);assertNotNull(users);assertTrue(users.stream().allMatch(user -> user.getAge() != null));}
结果
19.page(分页)
/*** 测试分页查询实体对象* 验证:返回的分页对象不为 null,且分页数据正确*/@Testpublic void testPage() {// 创建 QueryWrapper 对象QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByAsc("age"); // 按年龄升序排序// 创建分页对象Page<User> page = new Page<>(1, 3); // 第1页,每页3条// 执行分页查询Page<User> resultPage = userService.page(page, queryWrapper);// 打印分页结果System.out.println("===== 分页查询结果 =====");System.out.println("当前页码: " + resultPage.getCurrent());System.out.println("每页大小: " + resultPage.getSize());System.out.println("总记录数: " + resultPage.getTotal());System.out.println("总页数: " + resultPage.getPages());System.out.println("分页结果: ");for (User user : resultPage.getRecords()) { // 当前页的查询结果System.out.println("用户ID: " + user.getId() + ", 用户名: " + user.getName() + ", 年龄: " + user.getAge());}}
结果
如果结果不符合预期,可能是page插件未导入正确,需要手动配置一个配置类:
package com.example.mybatisplus.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 此配置类的作用是向 Spring 容器注册一个 MybatisPlusInterceptor 拦截器,* 该拦截器会在执行 SQL 时拦截分页查询语句,* 并自动处理分页逻辑,包含计算总记录数、总页数等。* */
@Configuration
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}
20.listMaps(获取所有数据)
/*** 测试获取实体对象的字段值列表* 验证:返回的字段值列表不为 null,且所有字段值符合条件*/@Testpublic void testListMaps() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByAsc("age");List<Map<String, Object>> maps = userService.listMaps(queryWrapper);System.out.println(maps);}
结果
list和listMaps的区别
list
方法(数据信息封装在实体类):
返回类型:
List<T>
,其中T
是实体类类型。用途:返回一个包含实体对象的列表,每个实体对象代表一条记录。
listMaps
方法(数据信息封装在map集合中):
返回类型:
List<Map<String, Object>>
。用途:返回一个包含
Map
的列表,每个Map
表示一条记录,键是字段名,值是字段值。
21.listObjs(获取某字段-不指定默认是主键id)
/*** 测试获取实体对象的字段值列表* 验证:返回的字段值列表不为 null,且所有字段值符合条件*/@Testpublic void testListObjs() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();// 指定要查询的列queryWrapper.select("name");// 使用 listObjs 方法获取 name 列的值List<Object> objNames = userService.listObjs(queryWrapper);System.out.println(objNames);}
结果
QueryWrapper
前面已经提到了QueryWrapper,现在来说一下QueryWrapper的常用方法:
方法 描述 示例 eq(String column, Object val)
等于(=) queryWrapper.eq("age", 20);
ne(String column, Object val)
不等于(<>) queryWrapper.ne("age", 20);
gt(String column, Object val)
大于(>) queryWrapper.gt("age", 20);
ge(String column, Object val)
大于等于(>=) queryWrapper.ge("age", 20);
lt(String column, Object val)
小于(<) queryWrapper.lt("age", 20);
le(String column, Object val)
小于等于(<=) queryWrapper.le("age", 20);
like(String column, Object val)
模糊查询(LIKE) queryWrapper.like("name", "张%");
notLike(String column, Object val)
模糊查询(NOT LIKE) queryWrapper.notLike("name", "张%");
in(String column, Collection<?> coll)
IN 查询 queryWrapper.in("age", Arrays.asList(20, 22, 24));
notIn(String column, Collection<?> coll)
NOT IN 查询 queryWrapper.notIn("age", Arrays.asList(20, 22, 24));
between(String column, Object val1, Object val2)
BETWEEN 查询 queryWrapper.between("age", 20, 24);
notBetween(String column, Object val1, Object val2)
NOT BETWEEN 查询 queryWrapper.notBetween("age", 20, 24);
orderByAsc(String column)
按字段升序排序(ASC) queryWrapper.orderByAsc("age");
orderByDesc(String column)
按字段降序排序(DESC) queryWrapper.orderByDesc("age");
and(Consumer<QueryWrapper<T>> consumer)
AND 条件嵌套 queryWrapper.and(wrapper -> wrapper.eq("age", 20).eq("name", "张三"));
or(Consumer<QueryWrapper<T>> consumer)
OR 条件嵌套 queryWrapper.or(wrapper -> wrapper.eq("age", 20).eq("name", "张三"));
isNotNull(String column)
判断字段不为 NULL queryWrapper.isNotNull("name");
isNull(String column)
判断字段为 NULL queryWrapper.isNull("name");
22.其他
/*** 测试使用 QueryChainWrapper 查询实体对象(并且只有一个)* 验证:查询成功后返回的实体对象不为 null*/@Testpublic void testQueryChainWrapper() {User user = userService.query().eq("name", "张三").one();assertNotNull(user);assertEquals("张三", user.getName());}/*** 测试使用 LambdaQueryChainWrapper 查询实体对象(并且符合的只有一个)* 验证:查询成功后返回的实体对象不为 null*/@Testpublic void testLambdaQueryChainWrapper() {User user = userService.lambdaQuery().eq(User::getName, "张三").one();assertNotNull(user);assertEquals("张三", user.getName());}/*** 测试使用 UpdateChainWrapper 更新实体对象* 验证:更新成功后返回 true*/@Testpublic void testUpdateChainWrapper() {boolean result = userService.update().eq("name", "张三").set("age", 30).update();assertTrue(result);}/*** 测试使用 LambdaUpdateChainWrapper 更新实体对象* 验证:更新成功后返回 true*/@Testpublic void testLambdaUpdateChainWrapper() {boolean result = userService.lambdaUpdate().eq(User::getName, "张三").set(User::getAge, 31).update();assertTrue(result);}/*** 测试保存或更新实体对象,并指定更新条件* 验证:保存或更新成功后返回 true*/@Testpublic void testSaveOrUpdateWithUpdateWrapper() {User user = new User();user.setId(1L); // 假设数据库中存在id为1的用户user.setName("更新后的名字");user.setAge(32);UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("id", user.getId());boolean result = userService.saveOrUpdate(user, updateWrapper);assertTrue(result);}
二、源码展示
当然,可以看一下上面这些方法的源码,在此注释中会详细介绍每个方法的概念和功能。
package com.baomidou.mybatisplus.extension.service;import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.kotlin.KtQueryChainWrapper;
import com.baomidou.mybatisplus.extension.kotlin.KtUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.transaction.annotation.Transactional;/*** 通用服务接口,提供基础的CRUD操作* @param <T> 实体类类型*/
public interface IService<T> {int DEFAULT_BATCH_SIZE = 1000;/*** 保存实体对象* @param entity 实体对象* @return 是否保存成功*/default boolean save(T entity) {return SqlHelper.retBool(this.getBaseMapper().insert(entity));}/*** 批量保存实体列表* @param entityList 实体列表* @return 是否保存成功*/@Transactional(rollbackFor = {Exception.class})default boolean saveBatch(Collection<T> entityList) {return this.saveBatch(entityList, 1000);}/*** 批量保存实体列表,可指定批量大小* @param entityList 实体列表* @param batchSize 批量大小* @return 是否保存成功*/boolean saveBatch(Collection<T> entityList, int batchSize);/*** 批量保存或更新实体列表* @param entityList 实体列表* @return 是否保存成功*/@Transactional(rollbackFor = {Exception.class})default boolean saveOrUpdateBatch(Collection<T> entityList) {return this.saveOrUpdateBatch(entityList, 1000);}/*** 批量保存或更新实体列表,可指定批量大小* @param entityList 实体列表* @param batchSize 批量大小* @return 是否保存成功*/boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);/*** 根据ID删除实体对象* @param id 实体ID* @return 是否删除成功*/default boolean removeById(Serializable id) {return SqlHelper.retBool(this.getBaseMapper().deleteById(id));}/*** 根据ID删除实体对象,可指定是否使用填充策略* @param id 实体ID* @param useFill 是否使用填充策略* @return 是否删除成功*/default boolean removeById(Serializable id, boolean useFill) {throw new UnsupportedOperationException("不支持的方法!");}/*** 根据实体对象删除* @param entity 实体对象* @return 是否删除成功*/default boolean removeById(T entity) {return SqlHelper.retBool(this.getBaseMapper().deleteById(entity));}/*** 根据条件Map删除* @param columnMap 条件Map* @return 是否删除成功*/default boolean removeByMap(Map<String, Object> columnMap) {Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));}/*** 根据条件删除* @param queryWrapper 条件* @return 是否删除成功*/default boolean remove(Wrapper<T> queryWrapper) {return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));}/*** 根据ID列表批量删除* @param list ID列表* @return 是否删除成功*/default boolean removeByIds(Collection<?> list) {return CollectionUtils.isEmpty(list) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(list));}/*** 根据ID列表批量删除,可指定是否使用填充策略* @param list ID列表* @param useFill 是否使用填充策略* @return 是否删除成功*/@Transactional(rollbackFor = {Exception.class})default boolean removeByIds(Collection<?> list, boolean useFill) {if (CollectionUtils.isEmpty(list)) {return false;} else {return useFill ? this.removeBatchByIds(list, true) : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(list));}}/*** 根据ID列表批量删除,可指定批量大小* @param list ID列表* @return 是否删除成功*/@Transactional(rollbackFor = {Exception.class})default boolean removeBatchByIds(Collection<?> list) {return this.removeBatchByIds(list, 1000);}/*** 根据ID列表批量删除,可指定批量大小和是否使用填充策略* @param list ID列表* @param useFill 是否使用填充策略* @return 是否删除成功*/@Transactional(rollbackFor = {Exception.class})default boolean removeBatchByIds(Collection<?> list, boolean useFill) {return this.removeBatchByIds(list, 1000, useFill);}/*** 根据ID列表批量删除,可指定批量大小和是否使用填充策略* @param list ID列表* @param batchSize 批量大小* @return 是否删除成功*/default boolean removeBatchByIds(Collection<?> list, int batchSize) {throw new UnsupportedOperationException("不支持的方法!");}/*** 根据ID列表批量删除,可指定批量大小和是否使用填充策略* @param list ID列表* @param batchSize 批量大小* @param useFill 是否使用填充策略* @return 是否删除成功*/default boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {throw new UnsupportedOperationException("不支持的方法!");}/*** 根据ID更新实体对象* @param entity 实体对象* @return 是否更新成功*/default boolean updateById(T entity) {return SqlHelper.retBool(this.getBaseMapper().updateById(entity));}/*** 根据条件更新* @param updateWrapper 条件* @return 是否更新成功*/default boolean update(Wrapper<T> updateWrapper) {return this.update((Object)null, updateWrapper);}/*** 根据条件更新实体对象* @param entity 实体对象* @param updateWrapper 条件* @return 是否更新成功*/default boolean update(T entity, Wrapper<T> updateWrapper) {return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));}/*** 根据ID列表批量更新* @param entityList 实体列表* @return 是否更新成功*/@Transactional(rollbackFor = {Exception.class})default boolean updateBatchById(Collection<T> entityList) {return this.updateBatchById(entityList, 1000);}/*** 根据ID列表批量更新,可指定批量大小* @param entityList 实体列表* @param batchSize 批量大小* @return 是否更新成功*/boolean updateBatchById(Collection<T> entityList, int batchSize);/*** 保存或更新实体对象* @param entity 实体对象* @return 是否保存成功*/boolean saveOrUpdate(T entity);/*** 根据ID获取实体对象* @param id 实体ID* @return 实体对象*/default T getById(Serializable id) {return this.getBaseMapper().selectById(id);}/*** 根据ID列表批量获取实体列表* @param idList ID列表* @return 实体列表*/default List<T> listByIds(Collection<? extends Serializable> idList) {return this.getBaseMapper().selectBatchIds(idList);}/*** 根据条件Map获取实体列表* @param columnMap 条件Map* @return 实体列表*/default List<T> listByMap(Map<String, Object> columnMap) {return this.getBaseMapper().selectByMap(columnMap);}/*** 根据条件获取单个实体对象* @param queryWrapper 条件* @return 实体对象*/default T getOne(Wrapper<T> queryWrapper) {return this.getOne(queryWrapper, true);}/*** 根据条件获取单个实体对象,可指定是否抛出异常* @param queryWrapper 条件* @param throwEx 是否抛出异常* @return 实体对象*/T getOne(Wrapper<T> queryWrapper, boolean throwEx);/*** 根据条件获取Map* @param queryWrapper 条件* @return Map*/Map<String, Object> getMap(Wrapper<T> queryWrapper);/*** 根据条件获取单个字段值* @param queryWrapper 条件* @param mapper 映射函数* @param <V> 字段值类型* @return 字段值*/<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);/*** 获取记录总数* @return 记录总数*/default long count() {return this.count(Wrappers.emptyWrapper());}/*** 根据条件获取记录总数* @param queryWrapper 条件* @return 记录总数*/default long count(Wrapper<T> queryWrapper) {return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));}/*** 根据条件获取实体列表* @param queryWrapper 条件* @return 实体列表*/default List<T> list(Wrapper<T> queryWrapper) {return this.getBaseMapper().selectList(queryWrapper);}/*** 获取所有实体列表* @return 实体列表*/default List<T> list() {return this.list(Wrappers.emptyWrapper());}/*** 分页查询* @param page 分页参数* @param queryWrapper 条件* @param <E> 分页类型* @return 分页结果*/default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {return this.getBaseMapper().selectPage(page, queryWrapper);}/*** 分页查询* @param page 分页参数* @param <E> 分页类型* @return 分页结果*/default <E extends IPage<T>> E page(E page) {return this.page(page, Wrappers.emptyWrapper());}/*** 根据条件获取Map列表* @param queryWrapper 条件* @return Map列表*/default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {return this.getBaseMapper().selectMaps(queryWrapper);}/*** 获取所有Map列表* @return Map列表*/default List<Map<String, Object>> listMaps() {return this.listMaps(Wrappers.emptyWrapper());}/*** 获取单个字段值列表* @return 字段值列表*/default List<Object> listObjs() {return this.listObjs(Function.identity());}/*** 根据条件获取单个字段值列表* @param mapper 映射函数* @param <V> 字段值类型* @return 字段值列表*/default <V> List<V> listObjs(Function<? super Object, V> mapper) {return this.listObjs(Wrappers.emptyWrapper(), mapper);}/*** 根据条件获取单个字段值列表* @param queryWrapper 条件* @return 字段值列表*/default List<Object> listObjs(Wrapper<T> queryWrapper) {return this.listObjs(queryWrapper, Function.identity());}/*** 根据条件获取单个字段值列表* @param queryWrapper 条件* @param mapper 映射函数* @param <V> 字段值类型* @return 字段值列表*/default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());}/*** 分页查询Map* @param page 分页参数* @param queryWrapper 条件* @param <E> 分页类型* @return 分页结果*/default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {return this.getBaseMapper().selectMapsPage(page, queryWrapper);}/*** 分页查询Map* @param page 分页参数* @param <E> 分页类型* @return 分页结果*/default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {return this.pageMaps(page, Wrappers.emptyWrapper());}/*** 获取基础Mapper* @return 基础Mapper*/BaseMapper<T> getBaseMapper();/*** 获取实体类类型* @return 实体类类型*/Class<T> getEntityClass();/*** 获取查询链式操作* @return 查询链式操作*/default QueryChainWrapper<T> query() {return ChainWrappers.queryChain(this.getBaseMapper());}/*** 获取Lambda查询链式操作* @return Lambda查询链式操作*/default LambdaQueryChainWrapper<T> lambdaQuery() {return ChainWrappers.lambdaQueryChain(this.getBaseMapper());}/*** 获取Kotlin查询链式操作* @return Kotlin查询链式操作*/default KtQueryChainWrapper<T> ktQuery() {return ChainWrappers.ktQueryChain(this.getBaseMapper(), this.getEntityClass());}/*** 获取Kotlin更新链式操作* @return Kotlin更新链式操作*/default KtUpdateChainWrapper<T> ktUpdate() {return ChainWrappers.ktUpdateChain(this.getBaseMapper(), this.getEntityClass());}/*** 获取更新链式操作* @return 更新链式操作*/default UpdateChainWrapper<T> update() {return ChainWrappers.updateChain(this.getBaseMapper());}/*** 获取Lambda更新链式操作* @return Lambda更新链式操作*/default LambdaUpdateChainWrapper<T> lambdaUpdate() {return ChainWrappers.lambdaUpdateChain(this.getBaseMapper());}/*** 保存或更新实体对象,可指定更新条件* @param entity 实体对象* @param updateWrapper 更新条件* @return 是否保存成功*/default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);}
}
想参考的可以看一下这个源码。
相关文章:
MyBatis-Plus(Ⅲ)IService详解
目录 一、逐一演示 1.save(插入一条) 结果 断言(引入概念) 2.saveBatch(批量插入) 结果 3.saveOrUpdateBatch(批量插入&更新) 结果 4.removeById(通过id删除…...
2024年认证杯SPSSPRO杯数学建模C题(第二阶段)云中的海盐全过程文档及程序
2024年认证杯SPSSPRO杯数学建模 C题 云中的海盐 原题再现: 巴黎气候协定提出的目标是:在2100年前,把全球平均气温相对于工业革命以前的气温升幅控制在不超过2摄氏度的水平,并为1.5摄氏度而努力。但事实上,许多之前的…...
PostgreSQL 存储过程
简介 PostgreSQL 中的存储过程(Stored Procedure)是一种在数据库中定义的可重复使用的程序单元,用于封装复杂的业务逻辑和数据处理操作 示例 简单示例 创建存储过程 CREATE PROCEDURE insert_users (user_account TEXT, hashed_password…...
GGUF 和 llama.cpp 是什么关系
这是个非常关键的问题,咱们来细说下:GGUF 和 llama.cpp 是什么关系,它们各自干什么,如何配合工作。 🔧 一、llama.cpp 是什么? llama.cpp 是 Meta 的开源大语言模型 LLaMA(Language Model from…...
(UI自动化测试web端)第二篇:元素定位的方法_class定位
看代码里的【 driver.find_element_by_class_name( )】()里的路径怎么写? 那我们现在说的就是在元素定位时,根据网页的实际情况来选择适合的元素定位的写法。文章主要介绍了class定位在正常工作当中的使用。 第三种定位 方式:class定位 ⽅法…...
闲聊IT - 面向服务架构(SOA)的发展历史
SOA的发展历史 面向服务架构(SOA)是随着企业信息化进程的发展逐渐形成的,它的出现是为了应对传统软件架构在现代企业复杂需求面前的局限性。SOA的起源和发展过程可以追溯到20世纪90年代末期,并随着互联网技术的普及、分布式计算以…...
31天Python入门——第9天:再学函数
你好,我是安然无虞。 文章目录 再学函数1. 变量在函数中的作用域2. 函数的参数传递.补充学习: 不定长参数*args和**kwargs 3. 值传递和引用传递补充学习: 把函数作为参数传递 4. 匿名函数5. python中内置的常用函数zip()map()filter()all()any() 6. 函数练习 再学函…...
卡特兰数在数据结构上面的运用
原理 Catalan数是一个数列,其第n项表示n个不同结点可以构成的二叉排序树的数量。Catalan数的第n项公式为:  其中,是组合数,表示从2n个元素中选择n个元素的组合数。 Catalan数的原理可以通过以下方式理解&…...
如何分析和解决服务器的僵尸进程问题
### 如何分析和解决服务器的僵尸进程问题 #### **一、僵尸进程的定义与影响** **僵尸进程(Zombie Process)** 是已终止但未被父进程回收资源的进程。其特点: - **状态标识**:在进程列表(如 ps 或 top)中标…...
Kafka分区分配策略详解
Kafka分区分配策略详解 Kafka作为当前最流行的分布式消息队列系统,其分区分配策略直接影响着系统的性能、可靠性和可扩展性。合理的分区分配不仅能够提高数据处理的效率,还能确保系统负载的均衡。 Kafka提供了多种内置的分区分配策略,包括R…...
Vs code搭建uniapp-vue项目
安装vue环境npm install -g vue/clinode版本建议18或者18以上 vue create -p dcloudio/uni-preset-vue 项目名称----正式版vue create -p dcloudio/uni-preset-vue#alpha 项目名称----alpha版Vue3/Vite版 npx degit dcloudio/uni-preset-vue#vite 项目名称---js-正式版npx degi…...
cursor常用快捷键(JetBrains Darcula主题风格)
一、基础操作速查 打开/创建项目 打开项目:Ctrl Shift O(选择文件夹)新建文件:Ctrl N保存文件:Ctrl S关闭当前标签页:Ctrl F4 代码编辑 复制当前行:Ctrl D删除当前行:Ctrl …...
easyExcel2.2.10中为0数据显示为空
在 EasyExcel 2.2.10 中,如果希望将数值为 0 的数据在 Excel 中显示为空(即不显示 0),可以通过以下方法实现: 1. 使用 ExcelProperty 的 format 参数 通过设置单元格格式为 #(# 会忽略 0)&…...
Walrus 经济模型 101
本文作者:Steve_4P,文章仅代表作者观点。 要点总结 2025 年 3 月 20 日,Walrus 基金会宣布成功融资 约 1.4 亿美元,投资方包括 Standard Crypto、a16z 等机构。Walrus 当前估值约 20 亿美元,其中 7% 代币供应量分配给…...
WordPress二次开发中常用到的一些变量和函数
WordPress是一个开源的博客软件平台,由于其强大的功能和灵活性,被广泛用于各种网站的建设。对于开发者来说,了解并掌握WordPress中的常用变量和函数是非常重要的。在WordPress二次开发中,以下是一些常用的变量和函数: …...
【视频】OpenCV:色彩空间转换、灰度转伪彩
1、颜色空间转换 使用OpenCV的函数 cv::applyColorMap 可以将灰度或者正常的RGB格式图片,转换成其它伪彩色,代码很简单: 1)使用 cv::imread 加载图片; 2)使用 std::vector<cv::Mat> matrices 暂存转换后的所有图像; 3)使用 cv::applyColorMap 转换图片颜色; 4)…...
淘宝历史价格数据获取指南:API 与爬虫方案的合法性与效率对比
引言 在淘宝平台的购物生态中,消费者希望通过了解商品历史价格来判断当前价格是否实惠,商家也需要借助历史价格数据制定合理的营销策略、分析市场趋势。获取淘宝商品历史价格数据主要有 API 和爬虫两种方案,它们在合法性与效率上存在显著差异…...
【Redis】高性能内存数据库的多场景应用
在现代互联网应用的开发版图中,Redis 凭借其卓越的性能和丰富的数据结构,成为了众多开发者不可或缺的技术利器。作为一款基于内存的高性能数据库,Redis 不仅能提供快速的数据读写操作,还能在多种复杂的应用场景中发挥关键作用。本…...
Pycharm社区版创建Flask项目详解
一、创建工程项目 二、配置工程目录 新建的空项目下创建目录。 1、新建app.py文件 2、app.py代码如下: from flask import Flask, render_templateapp Flask(__name__)app.route("/") def root():"""主页:return: Index.html"&qu…...
鸿蒙NEXT开发案例:程序员计算器
【环境准备】 • 操作系统:Windows 10 • 开发工具:DevEco Studio 5.0.1 Release Build Version: 5.0.5.306 • 目标设备:华为Mate60 Pro • 开发语言:ArkTS • 框架:ArkUI • API版本:API 13 【项目…...
TCP 三次握手与四次挥手过程
TCP 作为一种面向连接的、可靠的传输层协议,其连接管理机制对于保障数据的可靠传输至关重要。 三次握手(建立连接) 三次握手是 TCP 建立连接时所采用的机制,其目的在于确保客户端和服务器双方都具备发送和接收数据的能力&#x…...
仿新浪微博typecho主题源码
源码介绍 仿新浪微博typecho主题源码,简约美观,适合做个人博客,该源码为主题模板,需要先搭建typecho,然后吧源码放到对应的模板目录下,后台启用即可 源码特点 支持自适应 个性化程度高 可设置背景图、顶…...
python面试高频考点(深度学习大模型方向)
1. python中yeild和return的区别? 2. 介绍一下pytohn中的上下文管理器? 在Python中,上下文管理器(Context Manager) 是一种通过 with 语句管理资源的协议,确保资源(如文件、数据库连接、线程锁…...
【网络层协议】NAT技术内网穿透
IP地址数量限制 我们知道,IP地址(IPv4)是一个4字节32位的整数,那么一共只有2^32也就是接近43亿个IP地址,而TCP/IP协议栈规定,每台主机只能有一个IP地址,这就意味着,一共只有不到43亿…...
【数据分享】2000—2024年我国省市县三级逐年归一化植被指数(NDVI)数据(年平均值/Shp/Excel格式)
之前我们分享过2000-2024年我国逐年的归一化植被指数(NDVI)栅格数据,该逐年数据是取的当年月归一化植被指数(NDVI)的年平均值。!该数据来源于NASA定期发布的MOD13A3数据集!很多小伙伴拿到数据后…...
鸿蒙harmonyOS:笔记 正则表达式
从给出的文本中,按照既定的相关规则,匹配出符合的数据,其中的规则就是正则表达式,使用正则表达式,可以使得我们用简洁的代码就能实现一定复杂的逻辑,比如判断一个邮箱账号是否符合正常的邮箱账号࿰…...
centos7.9镜像源及Python引入ssl问题处理
一、镜像源修改 1. 备份原有的镜像源配置文件 在修改之前,先备份现有的 CentOS-Base.repo 文件: sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2. 编辑镜像源配置文件 使用文本编辑器(如 nano 或 vi)打开 /etc/yum.repos.d/Ce…...
【学Rust写CAD】11 2D CAD可用rust库
使用 Rust 开发 2D CAD 应用时,选择合适的库是关键。以下是一些适合用于 2D CAD 开发的 Rust 库和工具,涵盖图形渲染、几何计算、用户界面等方面: 图形渲染 lyon 简介: lyon 是一个用于 2D 图形渲染的 Rust 库,支持路径填充、描边…...
C#中值类型与引用类型是直观使用示例
一、值类型与引用类型区分 正确理解值类型与引用类型,可以更好的帮助软件开发人员写出性能更好且正确稳定运行的程序: C#值类型与引用类型区别 区别值类型引用类型定义所有继承自【System.ValueType】类型的都是值类型(valueType继承自Syste…...
Spring Cloud之负载均衡之LoadBalance
目录 负载均衡 问题 步骤 现象 什么是负载均衡? 负载均衡的一些实现 服务端负载均衡 客户端负载均衡 使用Spring Cloud LoadBalance实现负载均衡 负载均衡策略 编辑 编辑LoadBalancer原理 服务部署 准备环境和数据 服务构建打包 启动服务 上传J…...
MySQL的数据文件
MySQL的数据文件 mysql的数据都存放在datadir所指的位置,其中包含了mysql中创建的数据库,数据库中包含了表结构(frm文件)、表数据(myd文件)、表索引(myi文件) show variables like %datadir%.frm 存放和表相关的数据信息,主要包括表结构的定…...
【RabbitMQ高级特性】消息确认机制、持久化、发送方确认、TTL和死信队列
🔥个人主页: 中草药 🔥专栏:【中间件】企业级中间件剖析 一、消息确认机制 消费者确认机制确保消息被正确处理后才从队列中删除。如果消费者处理失败(如业务异常或宕机),Broker 会重新投递消息…...
C# 正则表达式
C# 正则表达式 引言 正则表达式(Regular Expression,简称Regex)是一种用于处理字符串的强大工具,在编程领域有着广泛的应用。C# 作为一种流行的编程语言,也内置了对正则表达式的支持。本文将详细介绍 C# 中的正则表达…...
第十四届蓝桥杯省赛电子类单片机学习记录(客观题)
01.一个8位的DAC转换器,供电电压为3.3V,参考电压2.4V,其ILSB产生的输出电压增量是(D)V。 A. 0.0129 B. 0.0047 C. 0.0064 D. 0.0094 解析: ILSB(最低有效位)的电压增量计算公式…...
23种设计模式-桥接(Bridge)设计模式
桥接设计模式 🚩什么是桥接设计模式?🚩桥接设计模式的特点🚩桥接设计模式的结构🚩桥接设计模式的优缺点🚩桥接设计模式的Java实现🚩代码总结🚩总结 🚩什么是桥接设计模式…...
AI重塑视觉艺术:DeepSeek与蓝耘通义万相2.1的图生视频奇迹
云边有个稻草人-CSDN博客 近年来,深度学习、计算机视觉和生成模型在多个领域取得了突破性进展。其中,DeepSeek与蓝耘通义万相2.1图生视频的结合为图像生成与视频生成技术提供了新的发展方向。DeepSeek作为一个图像和视频生成的工具,能够利用深…...
mac怎么安装pycharm?
安装步骤:1、打开PyCharm官网,在官网首页点击“下载”按钮,选择“MacOS”版本进行下载;2、双击打开安装包,将PyCharm拖动到应用程序文件夹中;3、根据提示进行安装,在第一次运行PyCharm时&#x…...
HTML应用指南:利用POST请求获取城市肯德基门店位置信息
随着新零售业态的快速发展,门店位置信息的获取变得越来越重要。作为快餐服务行业的先锋,肯德基不仅在服务质量上持续领先,还积极构建广泛的门店网络,以支持其不断增长的用户群体。为了更好地理解和利用这些数据,本篇文…...
Java主流开发框架之请求响应常用注释
1.RestController 标记一个类为 REST 控制器,处理 HTTP 请求并直接返回数据(如 JSON/XML),而不是视图(如 HTML),一般是放在类的上边 RestController public class UserController {GetMapping…...
go的参数传递都是值传递,但切片需要注意
根据之前学习python和java的经验,每次学习一门新语言时,一定要搞清楚方法的参数传递是值传递,引用传递还是指针传递。 主要原因就是需要知道,某种类型的数据传递给某个方法后,方法里面对它的修改是否会影响到这个数据本…...
C++菜鸟教程 - 从入门到精通 第五节
一.各种排序 接下来,让我们开始学习排序! 1.选择排序 a.原理简介 选择排序(Selection Sort)是一种简单直观的排序算法。它的基本思想是每次从未排序的部分中选择最小(或最大)的元素,将其放到已排序部分的末尾ÿ…...
同一个局域网的话 如何访问另一台电脑的ip
在局域网内访问另一台电脑,可以通过以下几种常见的方法来实现: 直接通过IP地址访问: 首先,确保两台电脑都连接在同一个局域网内。获取目标电脑的IP地址,这可以通过在目标电脑上打开命令提示符(Windows系…...
[学习笔记]攻防世界-bug
打开场景,提示我们需要登陆 我们先注册一下 注册成功 我们登陆进去 我们点击Manage他提示我们admin才能进入 我们刷新抓包一下试试 Cookie里面除了PHPSESSID,多出来了一个user,看上去是md5加密的,我们尝试解密 这里尝试了好几个网…...
[250324] Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft!| Wine 10.4 发布!
目录 Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft!Wine 10.4 发布! Kafka 4.0.0 版本发布:告别 ZooKeeper,拥抱 KRaft! 近日,Apache Kafka 4.0.0 正式发布!这是一个…...
【赵渝强老师】达梦数据库MPP集群的架构
为了支持海量数据存储和处理等方面的需求,为高端数据仓库提供解决方案,达梦数据库提供了大规模并行处理MPP架构,以极低的成本代价,提供高性能的并行计算。通过使用MPP可以解决以下问题: 需要较高的系统性能支持以支持…...
JWT 鉴权常见知识点及参考答案
JWT 鉴权常见知识点及参考答案 最近在 Go Web 项目当中使用到了 JWT 进行鉴权,因此通过这篇文章对 JWT 的原理及相关的知识点进行总结。 文章目录 JWT 鉴权常见知识点及参考答案JWT 签名算法的详细工作流程一. 签名的生成过程二. 签名的验证过程 1. 什么是 JWT&am…...
洛谷题单入门4-P5729 【深基5.例7】工艺品制作-python
输入格式 第一行三个正整数 w,x,h。 第二行一个正整数 q。 接下来 q 行,每行六个整数 输出格式 输出一个整数表示答案。 三维数组直接标记 class Solution:staticmethoddef oi_input():"""从标准输入读取数据"""w, x, h map(…...
【C语言】内存函数详解
个人主页 文章目录 🏠一、memcpy函数1.函数形式以及功能介绍2.函数的使用3.模拟实现 🚀二、memmove函数1.函数形式以及功能介绍2.函数的使用3.模拟实现 🎡三、memset函数1.函数形式以及功能介绍2.函数的使用 🎉四、memcmp1.函数形…...
使用Python开发自动驾驶技术:车道线检测模型
友友们好! 我是Echo_Wish,我的的新专栏《Python进阶》以及《Python!实战!》正式启动啦!这是专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会…...
HTTP代理的全面解读:什么是HTTP代理?HTTP代理的工作原理
在互联网大潮中,每一个请求和返回数据的背后,都离不开传输协议的支持,而HTTP协议无疑是最熟悉的网络通信基础之一。当我们谈到HTTP代理时,它不仅让浏览网络变得更高效,也为数据采集以及全球性远程任务提供了解决方案。…...