Hello, I’m Daming


One day I was at my desk listening to Vicotry, happily tapping hello World, and it felt like I was writing code that would take over the world. Out of the blue, operation gave me a call and said that one of our servers was OOM and asked me to go over and have a look. It felt like XXX, you know.

Go to the operation and maintenance room, log in to the server, view logs,…. A ton of operation fierce as tiger, see a List object 600MB + (forgive our server low, operation and maintenance is relatively stingy, GIVE 1C2G server), check the SQL statement at that time, a look, my darling, nearly 4000W + data. My first instinct was, which business is exporting large volumes of data again? However, all of our Excel exported data are verified, and the data volume is larger than 5W, and the data is exported in batches in the background (so sometimes you should be lucky that the server is low, because the server is low, you need to optimize all kinds of things, all operations with large data volume need to be optimized. So we this application has a variety of interesting SAO operation, there is a chance to share the next). Is it not under control? Looking at the log, there is no Excel export with large amount of data, so you can conclude that there is no paging where there is paging. Look at the code that found a pit in an if statement, as follows:

PageHelper.startPage(queryDTO.getPage(), queryDTO.getLimit());

Page<UserDTO> page;
if (isWitchFlag()) {
    page = userMapper.selectUserList(queryDTO);
}
Copy the code

isWitchFlag() :

    private boolean isWitchFlag(a) {
        String witchFlag = systemConfigMapper.selectSwitchFlag("key");
        return "1".equals(witchFlag);
    }
Copy the code

Those of you who are not familiar with PageHelper must not know where this pit is! In PageHelper using document (PageHelper. Making. IO/FAQ /) in the first sentence is expounded:

Only the first Mybatis query (Select) method following the pageHelper.startPage method will be paged. Please pay attention to keywords follow closely. Why follow? Since PageHelper uses a ThreadLocal for paging, its paging parameters are bound to the thread. When we execute pageHelper.startPage (), it binds the paging parameters to a ThreadLocal:

SetLocalPage () :

In the PageInterceptor, finally will remove the Page information:

Therefore, the paging information in the above code is consumed by the SELECT query in the if statement, and of course the paging information is not executed in the statements that actually require paging. How to solve it? Two options:

  • Treat the symptoms, not the causesWill:PageHelper.startPage()Move it inside the if statement so that the actual query statement is next to it. The reason why this scheme does not solve the root cause is that if there is a small partner who does not know the pit, it is possible to step on it.
  • Treat the symptoms: Use the Function Lamdba expression.

Use Function Lamdba toPageHelper.startPage()Close to paging query statements to avoid this pit

First we need to define a PageHelperTool that encapsulates paging statements:

@Builder
public class PageHelperTool<P.R> {
    private final Function<P, Page<R>> pageFunction;

    public Page<R> getPageInfo(P request) {
        PageHelper.startPage(((PageRequest)request).getPage(),((PageRequest)request).getLimit());
        returnpageFunction.apply(request); }}Copy the code

Then replace all pages with PageHelperTool:

        Page<UserDTO> page;
        if (isWitchFlag()) {
            PageHelperTool<QueryDTO,UserDTO> pageHelperTool = PageHelperTool.<QueryDTO,UserDTO>builder()
                                                            .pageFunction(userMapper::selectUserList)
                                                            .build();
            
            page = pageHelperTool.getPageInfo(queryDTO);
        }
Copy the code

This will solve the problem of page failure caused by misuse of PageHelper.

The last sentence: pay attention to the document !!!!!!