This is the third day of my participation in Gwen Challenge

I’m sure you’ve all used data pagination in your development process, so the question is, how many pagination methods do you usually use? PageHelper: PageHelper: github: IO/PageHelper: github: IO: PageHelper: github: IO: PageHelper: github: IO: PageHelper: github: IO: PageHelper: github: IO: PageHelper: github: IO: PageHelper: github: IO: PageHelper

Let’s start by talking about how to integrate and use itSpringbootAs an example)

Introduce dependencies in POM.xml

<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper-spring-boot-starter</artifactId>
	The < version > 1.3.0 < / version >
</dependency>
Copy the code

Introduce configuration in application.yml

pagehelper:
  helperDialect: mysql
  reasonable: true
  supportMethodsArguments: true
  params: count=countSql
Copy the code

Parameter interpretation

  1. HelperDialect: The paging plug-in will automatically detect the current database links and automatically select the appropriate paging method. You can configure the helperDialect property to specify which dialect to use for paging plug-ins. When configuring, you can use the following abbreviated values: oracle , mysql , mariadb , sqlite , hsqldb , postgresql , db2 , sqlserver , informix , h2 , sqlserver2012 , derby

    Note: If the SqlServer2012 database is used, manually set it to SqlServer2012; otherwise, SqlServer2005 will be used for paging. You can also implement an AbstractHelperDialect and configure this property to the fully qualified name of the implementation class to use your own custom implementation method.

  2. Reasonable: paging rationalization parameter. The default value is false. When this parameter is set to true, the first page is queried when pageNum<=0, and the last page is queried when pageNum> Pages exceeds the total number. If the default value is false, query is performed based on parameters.

  3. SupportMethodsArguments: Support paging parameters to be passed through Mapper interface parameters. The default value is false. The paging plug-in will automatically page when it finds an appropriate value from the parameter values in the query method, based on the values in the params configuration above.

  4. Params: In order to support the startPage (Object params) method, increased the parameters to configure the mapping, for according to the attribute names and values from the objects can be configured pageNum, pageSize, count, pageSizeZero, reasonable, If no mapping is configured, the default value is pageNum=pageNum. pageSize=pageSize; count=countSql; reasonable=reasonable; PageSizeZero = pageSizeZero.

The other parameters

  • OffsetAsPageNum: The default value isfalse, this parameter is used in pairsRowBoundsValid as a paging parameter. When this parameter is set totrueWhen will beRowBoundsIn theoffsetParameters aspageNumUse, you can use page number and page size parameters for paging.
  • RowBoundsWithCount: The default isfalse, this parameter is used in pairsRowBoundsValid as a paging parameter. When this parameter is set totrueWhen usingRowBoundsPaging does count queries.
  • PageSizeZero: Default value isfalseWhen this parameter is set totrueIf thepageSize=0orRowBounds.limit = 0All of the results will be queried (equivalent to no paging query, but the result is still returnedPageType).
  • AutoRuntimeDialect: The default isfalse. Set totrueAllows automatic identification of pages in dialects based on multiple data sources at run time. (Automatic selection is not supportedsqlserver2012, can only be usedsqlserver
  • CloseConn: The default value istrue. When using runtime dynamic data sources or not sethelperDialectProperty to automatically obtain a database connection. Use this property to set whether to close the obtained connection. DefaulttrueDisable, set tofalseAfter, the obtained connection is not closed. The setting of this parameter depends on the data source selected.

Method of use

@PostMapping("/list")
public PageInfo<ProductInfo> list(@RequestBody BasePage basePage){
	PageHelper.startPage(basePage.getPageNum(),basePage.getPageSize());
	List<ProductInfo> list = productInfoService.list(Wrappers.emptyWrapper());
	PageInfo<ProductInfo> productInfoPageInfo = new PageInfo<>(list);
	return productInfoPageInfo;
}
Copy the code

Returns the result

{
    "total": 3."list": [{"id": 1."name": "Passing by your whole world."."price": 32.0000."createDate": "2020-11-21T21:26:12"."updateDate": "2021-03-27T22:17:39"
        },
        {
            "id": 2."name": The Biography of Steve Jobs."price": 25.0000."createDate": "2020-11-21T21:26:42"."updateDate": "2021-03-27T22:17:42"}]."pageNum": 1."pageSize": 2."size": 2."startRow": 1."endRow": 2."pages": 2."prePage": 0."nextPage": 2."isFirstPage": true."isLastPage": false."hasPreviousPage": false."hasNextPage": true."navigatePages": 8."navigatepageNums": [
        1.2]."navigateFirstPage": 1."navigateLastPage": 2
}
Copy the code

Now let’s see how it implements paging, okay

First, say a small knowledge point:ThreadLocal

What is a ThreadLocal? What are the usage scenarios?

ThreadLocal is a Java class used to store local variables in a thread. ThreadLocal variables are variables that are limited within a thread and are owned by the thread itself. They are not shared by multiple threads.

Java provides a ThreadLocal class to support thread-local variables as a way to achieve thread-safety. However, be careful when using thread-local variables in a managed environment, such as a Web server, where the life of a worker thread is longer than the life of any application variable. Java applications run the risk of memory leaks if any thread-local variables are not released after work is done.

contrast

  • SynchronizedAccess conflicts are resolved by thread waiting, sacrificing time
  • ThreadLocalIs to resolve conflicts by giving each thread a separate piece of storage, sacrificing space, and comparing it toSynchronized.ThreadLocalHas the effect of thread isolation, only in the thread can get the corresponding value, outside the thread can not access the desired value.

Two, take a lookThreadLocalinPageHelperApplication in (directly to the code)

/** * The final method for paging calls **/
public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count,
                                    Boolean reasonable, Boolean pageSizeZero) {
    Page<E> page = new Page<E>(pageNum, pageSize, count);
    page.setReasonable(reasonable);
    page.setPageSizeZero(pageSizeZero);
    // When Order Derby has already been executed
    Page<E> oldPage = getLocalPage();
    if(oldPage ! =null && oldPage.isOrderByOnly()) {
        page.setOrderBy(oldPage.getOrderBy());
    }
    setLocalPage(page);
    return page;
}

// oldPage 
      
        oldPage = getLocalPage(); And setLocalPage (page); Method, they are looking at the current thread
      
. / / ThreadLocal ThreadLocalMap in the existence of the page object, if there is a direct, if there is no set an, we in the first, for example further


protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
/** * Get the Page parameter *@return* /
public static <T> Page<T> getLocalPage(a) {
    return LOCAL_PAGE.get();
}

public T get(a) {
    // Get the current thread
    Thread t = Thread.currentThread();
    // Get the ThreadLocalMap in the current thread
    ThreadLocalMap map = getMap(t);//ThreadLocal.ThreadLocalMap threadLocals = null;
    if(map ! =null) {
        //getEntry(ThreadLocal
      
        ThreadLocalMap.Entry e = map.getEntry(this);
        if(e ! =null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            returnresult; }}return setInitialValue();//=> t.threadLocals = new ThreadLocalMap(this, firstValue);
}

private Entry getEntry(ThreadLocal
        key) {
    // Use hashCode and the length bit to determine the index value I, which is stored in the table array
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];
    if(e ! =null && e.get() == key)
        return e;
    else
        return getEntryAfterMiss(key, i, e);
}

static class Entry extends WeakReference<ThreadLocal<? >>{
    /** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}Copy the code

Conclusion: We found that maintains in the Thread type for ThreadLocal. ThreadLocalMap threadLocals a parameters, it can be regarded as a special map, it is the key of ThreadLocal threadLocalHashCode, Value is the page information that we set. In fact, it maintains a table array with a size of 16 and a load factor of 2/3. Our data is stored in the Entry object of this table.

Knowledge:

1. The reason why WeakReference is set here is that if the common key-value form is used to define the storage structure, it will essentially cause the life cycle of the node to be strongly bound with the thread. As long as the thread is not destroyed, the node is always in the reachable state in GC analysis and cannot be recovered. The program itself has no way of determining whether a node can be cleaned up. Weak references are the third tier of four-file references in Java and are weaker than soft references. If an object does not have a strong reference chain reachable, it will generally not survive the next GC. When a ThreadLocal has no strong reference reachable, the key value of the corresponding Entry in the ThreadLocalMap becomes invalid as it is garbage collected, which facilitates garbage cleaning of the ThreadLocalMap itself.

2. For a ThreadLocal, its index value I is fixed, and different threads access the same position of different table array, namely table[I], but the table between different threads is independent.

3. For different ThreadLocal instances of the same thread, these ThreadLocal instances share an array of tables, and each ThreadLocal instance has a different index I in the table.

PageHelper actually intercepts SQL

When it comes to SQL interception function, we should think of Mybatis interceptor. Mybatis interceptor can intercept four types of objects:

  • Executor: The internal Executor of Mybatis that acts as the scheduling core and is responsible for calling StatementHandler to operate on the database and automatically mapping result sets through the ResultSetHandler
  • StatementHandler: encapsulates the JDBC Statement operation. It is the builder of SQL syntax and is responsible for interacting with the database to execute SQL statements
  • ParameterHandler: an object that handles SQL parameter Settings. It reads parameters and assigns values to parameters in PreparedStatement
  • ResultSetHandler: the interface object that processes the ResultSet returned after the Statement is executed. Mybatis uses this interface object to map the ResultSet set into entity objects

As you might have guessed, PageHelper also uses the Mybatis interceptor for pagination, so let’s take a look at the code.

// Focus only on key code
@Override
public Object intercept(Invocation invocation) throws Throwable {
    try{... resultList = ExecutorUtil.pageQuery(dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey); . }}public static <E> List<E> pageQuery(Dialect dialect, Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql, CacheKey cacheKey) throws SQLException {
        // Determine whether paging queries are required
        if (dialect.beforePage(ms, parameter, rowBounds)) {
            // Generate a cache key for paging
            CacheKey pageKey = cacheKey;
            // Process the parameter objectparameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey); . }}Copy the code

Get the Page object in ThreadLocal

@Override
public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) {...return processPageParameter(ms, paramMap, page, boundSql, pageKey);
 }
Copy the code

Put the paging data into the parameters, and then perform the paging logic

If you want to know how to use Mybatis interceptor, or think this article is helpful to you, you can pay attention to GZH “AH Q said code”, you can also add a friend Qingqing-4132 ah Q, AH Q look forward to your arrival!

Background message to get Java dry goods materials: study notes and big factory interview questions