整理一下 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,根据这个查询查询该条数据
*/
@Override
public 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查询
*/
@Override
public XxxDto getXxxById(Integer id) {
return this.to(xxxMapper.selectById(id));
}
写法三:(this.getById)
是 MyBatis-Plus 提供的方法
/**
* 根据订单Id查询该对象
*/
@Override
public 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查询一个列表集合
*/
@Override
public 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());
}
//实体类转Dto
private 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;
}
限制查询条数
@Override
public 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)
/**
* 单表分页查询
*/
@Override
public 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装备-分页查询
*/
@Override
public 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)
这种写法来构建多个查询条件比较不直观
@Override
public 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查询分组列表
*/
@Override
public List<AuthGroupServiceDto> selectListByPid(Integer pid) {
LambdaQueryWrapper<AuthGroupEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DsAuthGroupEntity::getPid, pid);
//如果 a.eq(AuthGroupEntity::getRules == “*”,则再查询 AuthGroupEntity::getPid == pid
wrapper.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
@Override
public 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”(不等于)的意思,表示查询的条件中要求某个字段的值不等于给定的值。
/**
* 查询管理员列表
*/
@Override
public 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)
@Override
public 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)
@Override
public 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 流中惊醒过滤的
/**
* 获取所有列表
*/
@Override
public 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)
@Override
public 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个骑手id
List<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 转 entity
List<DailyXxxEntity> businessList = allBusinessList.stream().map(this::to).collect(Collectors.toList());
//执行批量插入操作
return this.saveBatch(businessList);
}
单表修改
写法一:(update)
修改某个实体,这里是 new UpdateWrapper
@Override
public 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
*/
@Override
public Boolean updateXxx(XxxDto dto) {
if (dto == null) {
return null;
}
//把 dto转成entity,再执行修改操作
return this.updateById(this.to(dto));
}
写法三:(.setEntity 修改实体)
根据id修改整个实体对象
setEntity(…):这个方法是 UpdateWrapper 的一个调用,用于指定更新操作中使用的实体对象。调用 setEntity 后,更新操作会将指定实体的字段值更新到数据库中
/**
* 更新账户余额
*/
@Override
public 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 )
/**
* 增加账户余额
*/
@Override
public 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 更新该行数据指定的字段
/**
* 更新地址
*/
@Override
public 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信息
*/
@Override
public 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删除
/**
* 删除
*/
@Override
public boolean removeById(Long id) {
if (id == null) {
return false;
}
return super.removeById(id);
}
流操作
/**
* 获取订单小费
*/
@Override
public 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()