MyBaitsPlus 基本用法整理
- 查询
- 单表查询
- 查询单条数据
- 写法一:(this.getOne)
- 写法二:(XxxMapper.selectById)
- 写法三:(this.getById)
- 查询 list 集合(this.list)
- 查询所有
- 限制查询条数
- 分页查询(this.page)
- 单表模糊查询(like)
- 单表范围查询(in、between)
- 倒序查询(orderByDesc)
- 构建多个查询条件
- 写法一:(and 、or)
- 写法二:(or)
- 写法三:简单判断并构建查询条件
- 不等于(ne)
- 小于(le)
- 不为null
- 写法一:(isNotNull)
- 写法二:(filter)
- 单表批量查询(in)
- 单表分批批量查询(ListUtil.partition)★★★
- 新增或修改
- 单表新增
- 批量新增(saveBatch)
- 单表修改
- 写法一:(update)
- 写法二:(updateById)
- 写法三:(.setEntity 修改实体)
- 写法四:(.setSql 拼接sql )
- 更新指定字段(.set)
- 新增或修改(this.saveOrUpdate)
- 删除
- 写法一:(.removeBatchByIds)
- 写法二:(.remove)
- 写法三:( .removeById)
- 流操作
整理一下 MyBaitsPlus 的一点简单用法。
查询时:new QueryWrapper,QueryWrapper 是 MyBatis-Plus 中用于构建查询操作的条件封装类
修改是:new UpdateWrapper,UpdateWrapper 是 MyBatis-Plus 中用于构建更新操作的条件封装类
//查询
QueryWrapper<XxxWalletEntity> xxxWalletEntityQueryWrapper = new QueryWrapper<>();LambdaQueryWrapper<XxxWalletEntity> lambda = new QueryWrapper<XxxWalletEntity>().lambda();LambdaQueryWrapper<XxxWalletEntity> in = new QueryWrapper<XxxWalletEntity>().lambda().in(XxxWalletEntity::getAccountId, accountIds);
//修改
UpdateWrapper<XxxWalletEntity> updateWrapper = new UpdateWrapper<>();LambdaUpdateWrapper<XxxWalletEntity> lambda = new UpdateWrapper<XxxWalletEntity>().lambda();LambdaUpdateWrapper<XxxWalletEntity> eq = new UpdateWrapper<XxxWalletEntity>().lambda().eq(XxxWalletEntity::getAccountId, accountId);.setSql("balance = balance + " + balance));
查询
单表查询
查询单条数据
写法一:(this.getOne)
是 MyBatis-Plus 提供的方法
this.getOne 返回的是一条数据
/*** 根据用户id查询对象的数据* BusinessEntity 实体类对应的数据库表中有一个userId,根据这个查询查询该条数据*/@Overridepublic BusinessServiceDto getByUserId(Integer userId) {if (userId == null) {return null;}//根据id查询单条数据BusinessEntity businessEntity = this.getOne(new QueryWrapper<BusinessEntity>().lambda().eq(BusinessEntity::getUserId, userId));//to方法是实体类转Dto的方法return this.to(businessEntity);}
//这一步是构建查询对象
new QueryWrapper<BusinessEntity>().lambda().eq(BusinessEntity::getUserId, userId)//这一步是执行查询
this.getOne();
写法二:(XxxMapper.selectById)
是 MyBatis 的原生 Mapper 方法,尽管在 MyBatis-Plus 中也可以使用,但不是 MP 提供的
/*** 根据id查询*/@Overridepublic XxxDto getXxxById(Integer id) {return this.to(xxxMapper.selectById(id));}
写法三:(this.getById)
是 MyBatis-Plus 提供的方法
/*** 根据订单Id查询该对象*/@Overridepublic XxxOrderServiceDto getRiderXxxOrderById(Integer xxxOrderId) {if (xxxOrderId == null) {return null;}//获取对象XxxOrderEntity xxxOrderEntity = this.getById(xxxOrderId);//entity转serviceDto返回return this.to(xxxOrderEntity);}
查询 list 集合(this.list)
查询所有
this.list() 返回的是一个 list 集合
/*** 根据userId查询一个列表集合*/@Overridepublic List<UserServiceDto> getUserListByuserId(Integer userId) {//判空if (riderId == null) {return new ArrayList<>();}//查询List<UserEntity> list = this.list(new QueryWrapper<UserEntity>().lambda().eq(UserEntity::getUserId, userId));//将list集合中的实体类转成Dto类型再返回return list.stream().map(this::to).collect(Collectors.toList());}//实体类转Dtoprivate UserServiceDtoto(UserEntity entity) {if (entity == null) {return null;}UserServiceDtoto userServiceDtoto = new UserServiceDtoto();UserServiceDtoto.setId(entity.getId());//.......UserServiceDtoto.setRemark(entity.getRemark());UserServiceDtoto.setCreateTime(entity.getCreateTime());UserServiceDtoto.setUpdateTime(entity.getUpdateTime());return userServiceDtoto;}
限制查询条数
@Overridepublic List<XxxServiceDto> selectList() {List<XxxEntity> list = this.list(new QueryWrapper<XxxEntity>().lambda()//这表示数据库只会返回前 1000 条匹配的记录.last(" limit 1000"));return list.stream().map(this::to).collect(Collectors.toList());}
分页查询(this.page)
/*** 单表分页查询*/@Overridepublic PageInter<XxxServiceDto> getXxxList(String title, Integer status, PageParam pageParam) {//分页Page<XxxEntity> page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());//mp单表查询Page<XxxEntity> pageList = this.page(page, new QueryWrapper<XxxEntity>().lambda()//如果title不为空,则执行查询.like(ObjectUtil.isNotEmpty(title), XxxEntity::getTitle, title)//如果status不为空,则执行查询.eq(ObjectUtil.isNotEmpty(status), XxxEntity::getStatus, status)//根据时间进行倒序.orderByDesc(XxxEntity::getAddTime));return PageInter.to(pageList, this::to);}
mp工具类里面的翻页查询方法-- page方法源码
备注:如果是调用分页查询的方法(SQL连表查询),但是想得到不分页的list集合,Page参数可以这么设置,list可以用getRecords()方法获取
//如果调用分页查询的方法,相要得到不分页的list集合,那么这个分页参数对象的参数可以这样设置Page<XxxDto> page = new Page<>(1, -1);//查询,得到的是一个分页对象page = xxxMapper.getXxxList(page, xx, xx, xx);//从分页对象获取list集合List<XxxDto> list = page.getRecords();
其他示例
/*** Xxx商场-Xxx装备-分页查询*/@Overridepublic PageInter<XxxServiceDto> getRiderXxxList(String title, Integer status, PageParam pageParam) {//分页Page<XxxEntity> page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());//mp单表查询Page<XxxEntity> pageList = this.page(page, new QueryWrapper<XxxEntity>().lambda().like(ObjectUtil.isNotEmpty(title), XxxEntity::getTitle, title).eq(ObjectUtil.isNotEmpty(status), XxxEntity::getStatus, status).orderByDesc(XxxEntity::getAddTime));return PageInter.to(pageList, this::to);}
单表模糊查询(like)
//如果title不为空,则执行查询
.like(ObjectUtil.isNotEmpty(title), XxxEntity::getTitle, title)
单表范围查询(in、between)
//IN 用于检查某个值是否在指定的集合中
//判断ids不为空,然后获取XxxEntity实体类的id,且需要该id存在Ids集合中
.in(CollUtil.isNotEmpty(Ids), XxxEntity::getId, Ids)
//查找状态为 0 或 2 的记录
.in(XxxEntity::getStatus, 0, 2)
//BETWEEN 用于检查某个值是否在两个指定值之间(包括这两个值).between(dateStart != null && dateEnd != null, XxxEntity::getCreateTime, dateStart, dateEnd));
倒序查询(orderByDesc)
//根据addTime进行倒序查询
.orderByDesc(XxxEntity::getAddTime)
构建多个查询条件
写法一:(and 、or)
这种写法来构建多个查询条件比较不直观
@Overridepublic PageInter<AccountMovementLogServiceDto> getXxxxxxLog(Integer businessId, PageParam pageParam) {//分页对象Page<AccountMovementLogEntity> page = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());//分页单表查询page = this.page(page, new QueryWrapper<AccountMovementLogEntity>().lambda().and(wrapper -> wrapper.eq(businessId != null, AccountMovementLogEntity::getMovementId, businessId)// 该商家是资金移动方.eq(AccountMovementLogEntity::getMovementType, AccountMovementLogType.BUSINESS.getType())).or(wrapper -> wrapper.eq(businessId != null, AccountMovementLogEntity::getReceiveId, businessId)// 该商家是资金接收方.eq(AccountMovementLogEntity::getReceiveType, AccountMovementLogType.BUSINESS.getType())).orderByDesc(AccountMovementLogEntity::getCreateTime));//entity 转 dto 再返回return PageInter.to(page, this::to);}
写法二:(or)
/*** 根据Pid查询分组列表*/@Overridepublic List<AuthGroupServiceDto> selectListByPid(Integer pid) {LambdaQueryWrapper<AuthGroupEntity> wrapper = new LambdaQueryWrapper<>();wrapper.eq(DsAuthGroupEntity::getPid, pid);//如果 a.eq(AuthGroupEntity::getRules == “*”,则再查询 AuthGroupEntity::getPid == pidwrapper.or(a -> a.eq(AuthGroupEntity::getRules, "*").and(b -> b.eq(AuthGroupEntity::getPid, pid)));return this.list(wrapper).stream().map(this::to).collect(Collectors.toList());}
写法三:简单判断并构建查询条件
直接if条件判断,然后再把查询条件构建到 LambdaQueryWrapper 对象即可,最后再用 this.list() 执行查询,再调用 .stream() 方法把entity 转成 dto
@Overridepublic List<XxxServiceDto> selectXxxList(ArchiveParam param) {LambdaQueryWrapper<XxxEntity> queryWrapper = new QueryWrapper<XxxEntity>().lambda()//使用 select(XxxEntity::getId) 指定查询结果只返回 XxxEntity 中的 id 字段,因此查询将返回一个 id 列表.select(XxxEntity::getId).in(CollUtil.isNotEmpty(param.getIds()), XxxEntity::getId, param.getIds());//根据条件判断,构建查询条件if (param.getBegin() != null) {queryWrapper.ge(XxxEntity::getDateTime, param.getBegin());}if (param.getEnd() != null) {queryWrapper.le(XxxEntity::getDateTime, param.getEnd());}//调用 this.list() 方法执行查询,得到一个元素为 XxxEntity 类型的 list 集合return this.list(queryWrapper)//将集合(如列表、集合等)转换为流(Stream)对象.stream()//调用当前类中的 to 方法进行转换,具体是把 XxxEntity 转成成 dto。.map(this::to)//将转换后的结果收集到一个列表中并返回.collect(Collectors.toList());}
上面的这个select 和 in 构建的查询条件类似于如下:只查询id
SELECT id FROM XxxEntity WHERE id IN (value1, value2, ..., valueN);
不等于(ne)
.ne(…):这个方法代表 “not equal”(不等于)的意思,表示查询的条件中要求某个字段的值不等于给定的值。
/*** 查询管理员列表*/@Overridepublic List<AdminXxxxxDto> getAdminList() {List<AdminEntity> list = this.list(new LambdaQueryWrapper<AdminEntity>().eq(AdminEntity::getStatus, 1).ne(AdminEntity::getCityId, 0));return list.stream().map(this::to).collect(Collectors.toList());}
小于(le)
小于等于:le (less than or equal to)
大于:gt (greater than)
@Overridepublic List<XxxServiceDto> getTaskList() {List<XxxEntity> list = this.list(new QueryWrapper<XxxEntity>().lambda()//日期判断,小于.le(XxxEntity::getCompTime, new Date())//查找状态为 0 或 2 的记录.in(XxxEntity::getStatus, 0, 2)//限制查询结果为最多 100 条.last(" limit 100"));return list.stream().map(this::to).collect(Collectors.toList());}
不为null
写法一:(isNotNull)
@Overridepublic List<CityServiceDto> getCityInfoList(Boolean examinable, Boolean expire, Boolean normality) {List<DsCityEntity> list = this.list(new QueryWrapper<CityEntity>().lambda().eq(CityEntity::getIsDisabled, 0).eq(examinable != null, CityEntity::isExaminable, examinable).eq(expire != null, CityEntity::isExpire, expire).eq(normality != null, CityEntity::isNormalCity, normality).isNotNull(CityEntity::getMapLatLng).ne(CityEntity::getMapLatLng, ""));return list.stream().map(this::to).collect(Collectors.toList());}
写法二:(filter)
这个是在 stream 流中惊醒过滤的
/*** 获取所有列表*/@Overridepublic List<DevelopApisServiceDto> getList(String suggest) {List<DevelopApisEntity> list = this.list(new QueryWrapper<DevelopApisEntity>().lambda().like(StrUtil.isNotBlank(suggest), DevelopApisEntity::getName, suggest));return list.stream().map(this::to).filter(Objects::nonNull).collect(Collectors.toList());}
.isNotNull(…):是 mp 的从数据库中查出非null的数据;
filter(Objects::nonNull): 是把查询来的数据,在内存中再进行一次处理
单表批量查询(in)
@Overridepublic Map<Integer, String> getNameBatch(List<Integer> ids) {if (CollUtil.isEmpty(ids)) {return new HashMap<>();}List<CityEntity> list = this.list(new QueryWrapper<CityEntity>().lambda().in(CityEntity::getId, ids));return list.stream().collect(Collectors.toMap(CityEntity::getId, CityEntity::getName));}
单表分批批量查询(ListUtil.partition)★★★
/*** 根据骑手ids集合批量查询*/
@Override
public Map<Integer, RiderBindServiceDto> getBindByRiderIds(List<Integer> riderIds) {if (CollUtil.isEmpty(riderIds)) {return new HashMap<>();}//把骑手ids集合分区,一个list元素存100个骑手idList<List<Integer>> partition = ListUtil.partition(riderIds, 100);Map<Integer, RiderBindServiceDto> bindServiceDtoMap = partition.stream().map(v -> this.list(new QueryWrapper<DsRiderBindEntity>().lambda().in(DsRiderBindEntity::getRiderId, v))).flatMap(Collection::stream).map(this::to).collect(Collectors.toMap(RiderBindServiceDto::getRiderId, Function.identity()));return bindServiceDtoMap;
}
解释:
新增或修改
单表新增
批量新增(saveBatch)
把 list 集合的数据新增到数据库,需要把集合的对象先转成 entity 实体类
@Override@Transactional(rollbackFor = Exception.class)public boolean insertXxxList(List<DailyXxxDto> allBusinessList) {//dto 转 entityList<DailyXxxEntity> businessList = allBusinessList.stream().map(this::to).collect(Collectors.toList());//执行批量插入操作return this.saveBatch(businessList);}
单表修改
写法一:(update)
修改某个实体,这里是 new UpdateWrapper
@Overridepublic boolean updateFlag(Integer cityId, boolean examinablexxx, boolean expirexxx, boolean normalCityxxx) {if (cityId == null) {return false;}return this.update(new UpdateWrapper<CityEntity>().lambda().set(CityEntity::isExaminablexxx, examinablexxx).set(CityEntity::isExpirexxx, expirexxx).set(CityEntity::isNormalCityxxx, normalCityxxx).eq(CityEntity::getId, cityId));}
写法二:(updateById)
/*** 修改Xxx根据Id*/@Overridepublic Boolean updateXxx(XxxDto dto) {if (dto == null) {return null;}//把 dto转成entity,再执行修改操作return this.updateById(this.to(dto));}
写法三:(.setEntity 修改实体)
根据id修改整个实体对象
setEntity(…):这个方法是 UpdateWrapper 的一个调用,用于指定更新操作中使用的实体对象。调用 setEntity 后,更新操作会将指定实体的字段值更新到数据库中
/*** 更新账户余额*/@Overridepublic boolean updateAccount(XxxWalletDto dto) {if (dto == null) {return false;}XxxWalletEntity entity = this.to(dto);return this.update(new UpdateWrapper<XxxWalletEntity>().lambda().eq(XxxWalletEntity::getAccountId, entity.getAccountId()).setEntity(this.to(dto)));}
写法四:(.setSql 拼接sql )
/*** 增加账户余额*/@Overridepublic boolean addWallet(Integer accountId, BigDecimal balance) {// 加锁LockUtil.openAccountBalance(accountId, () -> {if (accountId == null || BigDecimal.ZERO.compareTo(balance) >= 0) {throw BizException.newInstance(ErrorCode.ARGUMENT_ERROR);}// 这个执行修改的对应的sql语句:// UPDATE xxx_wallet_entity SET balance = balance + ? WHERE account_id = ?this.update(new UpdateWrapper<XxxWalletEntity>().lambda().eq(XxxWalletEntity::getAccountId, accountId).setSql("balance = balance + " + balance));}, () -> {throw BizException.newInstance(ErrorCode.BUSY);});return true;}
更新指定字段(.set)
通过 id 更新该行数据指定的字段
/*** 更新地址*/@Overridepublic boolean xxxUpdateAddress(Integer orderId, String address, LocationDto location) {if (orderId == null || location == null) {return false;}return this.update(new UpdateWrapper<XxxAddressEntity>().lambda().set(XxxAddressEntity::getEndAddress, address).set(XxxAddressEntity::getEndLat, location.getLatitude()).set(XxxAddressEntity::getEndLng, location.getLongitude()).eq(XxxAddressEntity::getOrderId, orderId));}
this.update 执行修改操作后生成的 sql 示例:
UPDATE xxx_address
SET end_address = '某地地址', end_lat = 30.123456, end_lng = 120.654321
WHERE order_id = 123
新增或修改(this.saveOrUpdate)
更具对象是否有id来判断是新增还是修改
/*** Xxx商场-Xxx装备-添加/编辑*/@Override@Transactional(rollbackFor = Exception.class)public boolean xxxSaveOrUpdate(XxxServiceDto xxxServiceDto) {//把Dto转成Entity,调用mp方法执行添加和编辑操作return this.saveOrUpdate(this.to(xxxServiceDto));}
删除
写法一:(.removeBatchByIds)
根据ids集合,进行删除,可以单个也可批量。
/*** 商城-商城订单-删除(单个/批量)*/@Override@Transactional(rollbackFor = Exception.class)public boolean deleteXxxOrderById(List<Integer> ids) {if (ids == null || ids.isEmpty()){return false;}return this.removeBatchByIds(ids);}
写法二:(.remove)
使用了 MyBatis-Plus 的 remove 方法和 QueryWrapper 来构建删除条件
/*** 根据id删除xxx信息*/@Overridepublic boolean removeByRiderIds(List<XxxServiceDto> riderList) {if (CollUtil.isEmpty(riderList)) {return false;}List<Integer> riderIds = riderList.stream().map(XxxServiceDto::getRiderId).collect(Collectors.toList());// 执行删除方法return this.remove(new QueryWrapper<XxxEntity>().lambda().in(XxxEntity::getRiderId, riderIds));}
写法三:( .removeById)
根据id删除
/*** 删除*/@Overridepublic boolean removeById(Long id) {if (id == null) {return false;}return super.removeById(id);}
流操作
/*** 获取订单小费*/@Overridepublic BigDecimal getOrderTips(Integer orderId) {if (orderId == null) {return BigDecimal.ZERO;}List<XxxOrderTipEntity> list = this.list(new QueryWrapper<XxxOrderTipEntity>().lambda().eq(XxxOrderTipEntity::getOid, orderId).eq(XxxOrderTipEntity::getBusiPay, 1).eq(XxxOrderTipEntity::getIsPay, 1).eq(XxxOrderTipEntity::getIsUse, 1));//使用 Java Stream API 对小费记录进行处理:Optional<Integer> amount = list.stream()// filter 方法用于过滤掉 amount 为 null 或 0 的记录.filter(v -> v.getAmount() != null && v.getAmount() != 0)// map 方法提取每个有效小费的 amount 值.map(XxxOrderTipEntity::getAmount)// 使用 reduce 方法将流中的所有金额进行累加// Integer::sum 是一个方法引用,用于将流中的所有元素相加,最终返回一个 Optional<Integer>.reduce(Integer::sum);return amount.map(integer -> new BigDecimal(integer)// new BigDecimal(100) 是除数,表示将金额从分转换为元。// 2 表示结果保留两位小数。// RoundingMode.DOWN:指定取整模式为向下取整,这意味着在小数点后超出的部分会被舍去.divide(new BigDecimal(100), 2, RoundingMode.DOWN))// 如果 amount 是空的(即没有有效小费记录),orElse 方法将返回 BigDecimal.ZERO,表示小费总额为零.orElse(BigDecimal.ZERO);}
divide 是 BigDecimal 类中的一个方法,用于执行除法运算。具体来说,divide 方法的作用是将一个 BigDecimal 对象除以另一个 BigDecimal 对象,并返回一个新的 BigDecimal 结果
.orElse(BigDecimal.ZERO) 的解释:
如果 list 中没有任何满足过滤条件的 XxxOrderTipEntity 对象(即没有有效的小费金额),则流操作将不会产生任何元素,最终的 reduce 方法返回的是 Optional.empty()