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 itSpringboot
As 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
-
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.
-
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.
-
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.
-
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 is
false
, this parameter is used in pairsRowBounds
Valid as a paging parameter. When this parameter is set totrue
When will beRowBounds
In theoffset
Parameters aspageNum
Use, you can use page number and page size parameters for paging. - RowBoundsWithCount: The default is
false
, this parameter is used in pairsRowBounds
Valid as a paging parameter. When this parameter is set totrue
When usingRowBounds
Paging does count queries. - PageSizeZero: Default value is
false
When this parameter is set totrue
If thepageSize=0
orRowBounds.limit = 0
All of the results will be queried (equivalent to no paging query, but the result is still returnedPage
Type). - AutoRuntimeDialect: The default is
false
. Set totrue
Allows 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 is
true
. When using runtime dynamic data sources or not sethelperDialect
Property to automatically obtain a database connection. Use this property to set whether to close the obtained connection. Defaulttrue
Disable, set tofalse
After, 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
Synchronized
Access conflicts are resolved by thread waiting, sacrificing timeThreadLocal
Is to resolve conflicts by giving each thread a separate piece of storage, sacrificing space, and comparing it toSynchronized
.ThreadLocal
Has 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 lookThreadLocal
inPageHelper
Application 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