背景 我們的springboot應用程式的持久層,是用jeecgboot框架生成的代碼。mybatisplus版本是3.1.2。 在一次對當前程式的sql性能優化時,我重寫了BaseMapper的selectPage方法。其中,為Wrapper<T>參數加上了id限制,以提高sql執行性能。 imp ...
背景
我們的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