没用好mybatisplus的Wrapper,我真难为情啊

背景

我们的springboot应用程序的持久层,是用jeecgboot框架生成的代码。mybatisplus版本是3.1.2。

 

在一次对当前程序的sql性能优化时,我重写了BaseMapper的selectPage方法。其中,为Wrapper<T>参数加上了id限制,以提高sql执行性能。

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface SbhPlatOrderMapper extends BaseMapper<SbhPlatOrder> { 
 @Override
 default IPage<SbhPlatOrder> selectPage(IPage<SbhPlatOrder> page, @Param(Constants.WRAPPER) Wrapper<SbhPlatOrder> queryWrapper){
 PrePageDto prePageDto = selectCountCache(queryWrapper);
 page.setTotal(prePageDto.getRowCount());
 if (prePageDto.getRowCount()>0) {
 if (queryWrapper instanceof LambdaQueryWrapper) {
 ((LambdaQueryWrapper<SbhPlatOrder>) queryWrapper).between(SbhPlatOrder::getId, prePageDto.getMinId(), prePageDto.getMaxId());
 } else if (queryWrapper instanceof QueryWrapper) {
 ((QueryWrapper<SbhPlatOrder>) queryWrapper).lambda().between(SbhPlatOrder::getId, prePageDto.getMinId(), prePageDto.getMaxId());
 }
 page.setRecords(selectPageList((page.getCurrent() - 1) * page.getSize(), page.getSize(), queryWrapper));
 }
 return page;
 }
 
 @Cacheable(cacheNames = RedisConfig.SBH_PLAT_ORDER_COUNT_CACHE_KEY,
 key = "T(com.emax.zhenghe.common.util.security.MD5Util).md5Encode(#queryWrapper.customSqlSegment)")
 PrePageDto selectCountCache(@Param(Constants.WRAPPER) Wrapper<SbhPlatOrder> queryWrapper);
 。。。
}

 

问题描述

程序上线后运行了一段时间。后来,发现了一个问题。见下面日志截图

 

 

原来呢,service类里调用这个分页的方法里,并不是每次调用分页时都new一个Wrapper对象,而是重复使用一个Wrapper对象。 所以,出现上图的问题就不难理解了。

 

 

 

解决办法 -Wrapper#getCustomSqlSegment

头疼医头的方式,是修改service类里调用这个分页的方法,每次调用分页前都new一个Wrapper对象。

显然,这样解决问题只是一时。以后再有调用这个分页的地方,依然会存在这个问题呀。

所以,我的解决办法是利用 Wrapper#getCustomSqlSegment, 上面sql里重复出现的是 id BETWEEN。所以,修正的代码如下:

// 外面调用处可能复用这个queryWrapper对象。所以,为避免重复追加条件,这里先做判读再追加。
 if (!queryWrapper.getCustomSqlSegment().contains("id BETWEEN")) {
 if (queryWrapper instanceof LambdaQueryWrapper) {
 ((LambdaQueryWrapper<SbhPlatOrder>) queryWrapper).between(SbhPlatOrder::getId, prePageDto.getMinId(), prePageDto.getMaxId());
 } else if (queryWrapper instanceof QueryWrapper) {
 ((QueryWrapper<SbhPlatOrder>) queryWrapper).lambda().between(SbhPlatOrder::getId, prePageDto.getMinId(), prePageDto.getMaxId());
 }
 }

 

更好的解决办法-Wrapper#clone

利用clone方法。mybatisplus的Wrapper的抽象父类AbstractWrapper,重写了超类Object的clone方法。如下是源码:

package com.baomidou.mybatisplus.core.conditions;
public abstract class AbstractWrapper ...{
 @Override
 @SuppressWarnings("all")
 public Children clone() {
 return SerializationUtils.clone(typedThis);
 }
}

相比上面的解决办法,我认为这是更好的解决办法,这样修正的代码如下:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface SbhPlatOrderMapper extends BaseMapper<SbhPlatOrder> { 
 @Override
 default IPage<SbhPlatOrder> selectPage(IPage<SbhPlatOrder> page, @Param(Constants.WRAPPER) Wrapper<SbhPlatOrder> queryWrapper){
 Wrapper<SbhPlatOrder> queryWrapperClone = queryWrapper.clone();
 PrePageDto prePageDto = selectCountCache(queryWrapperClone);
 page.setTotal(prePageDto.getRowCount());
 if (prePageDto.getRowCount()>0) {
 if (queryWrapperClone instanceof LambdaqueryWrapperClone) {
 ((LambdaQueryWrapper<SbhPlatOrder>) queryWrapperClone).between(SbhPlatOrder::getId, prePageDto.getMinId(), prePageDto.getMaxId());
 } else if (queryWrapperClone instanceof QueryWrapper) {
 ((QueryWrapper<SbhPlatOrder>) queryWrapperClone).lambda().between(SbhPlatOrder::getId, prePageDto.getMinId(), prePageDto.getMaxId());
 }
 page.setRecords(selectPageList((page.getCurrent() - 1) * page.getSize(), page.getSize(), queryWrapperClone));
 }
 return page;
 }
 。。。
}

 

EOF-thanks!

作者:buguge原文地址:https://www.cnblogs.com/buguge/p/16940068.html

%s 个评论

要回复文章请先登录注册