1 // 組裝查詢條件 2 ArticleVO articleVO = new ArticleVO(); 3 articleVO.setAuthor("劉慈欣"); 4 5 // 初始化返回類 6 // ResponsePages類是這樣一種返回類,其中包括返回代碼code和返回消息msg 7 // 還包括返回的數據和分頁信息 8 // 其中,分頁信息就是 com.github.pagehelper.Page<?> 類型 9 ResponsePages<List<ArticleVO>> responsePages = new ResponsePages<>(); 10 11 // 這裏爲了簡單,寫死分頁參數。正確的作法是從查詢條件中獲取 12 // 假設須要獲取第1頁的數據,每頁20條記錄 13 // com.github.pagehelper.Page<?> 類的基本字段以下 14 // pageNum: 當前頁 15 // pageSize: 每頁條數 16 // total: 總記錄數 17 // pages: 總頁數 18 com.github.pagehelper.Page<?> page = PageHelper.startPage(1, 20); 19 20 // 根據條件獲取文章列表 21 List<ArticleVO> articleList = articleMapper.getArticleListByCondition(articleVO); 22 23 // 設置返回數據 24 responsePages.setData(articleList); 25 26 // 設置分頁信息 27 responsePages.setPage(page);
1 /** 2 * 開始分頁 3 * 4 * @param pageNum 頁碼 5 * @param pageSize 每頁顯示數量 6 * @param count 是否進行count查詢 7 * @param reasonable 分頁合理化,null時用默認配置 8 * @param pageSizeZero true 且 pageSize=0 時返回所有結果,false時分頁, null時用默認配置 9 */ 10 public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) { 11 Page<E> page = new Page<E>(pageNum, pageSize, count); 12 page.setReasonable(reasonable); 13 page.setPageSizeZero(pageSizeZero); 14 // 當已經執行過orderBy的時候 15 Page<E> oldPage = SqlUtil.getLocalPage(); 16 if (oldPage != null && oldPage.isOrderByOnly()) { 17 page.setOrderBy(oldPage.getOrderBy()); 18 } 19 SqlUtil.setLocalPage(page); 20 return page; 21 }
1 package com.github.pagehelper.util; 2 ... 3 4 public class BaseSqlUtil { 5 // 省略其餘代碼 6 7 private static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>(); 8 9 /** 10 * 從 ThreadLocal<Page> 中獲取 page 11 */ 12 public static <T> Page<T> getLocalPage() { 13 return LOCAL_PAGE.get(); 14 } 15 16 /** 17 * 將 page 設置到 ThreadLocal<Page> 18 */ 19 public static void setLocalPage(Page page) { 20 LOCAL_PAGE.set(page); 21 } 22 23 // 省略其餘代碼 24 }
1 package org.apache.ibatis.binding; 2 ... 3 4 public class MapperMethod { 5 6 public Object execute(SqlSession sqlSession, Object[] args) { 7 Object result; 8 if (SqlCommandType.INSERT == command.getType()) { 9 // 省略 10 } else if (SqlCommandType.UPDATE == command.getType()) { 11 // 省略 12 } else if (SqlCommandType.DELETE == command.getType()) { 13 // 省略 14 } else if (SqlCommandType.SELECT == command.getType()) { 15 if (method.returnsVoid() && method.hasResultHandler()) { 16 executeWithResultHandler(sqlSession, args); 17 result = null; 18 } else if (method.returnsMany()) { 19 /** 20 * 獲取多條記錄 21 */ 22 result = executeForMany(sqlSession, args); 23 } else if ... 24 // 省略 25 } else if (SqlCommandType.FLUSH == command.getType()) { 26 // 省略 27 } else { 28 throw new BindingException("Unknown execution method for: " + command.getName()); 29 } 30 ... 31 32 return result; 33 } 34 }
# sqlSessionFactory 中的重要信息
sqlSessionFactory
configuration
environment
mapperRegistry
config
knownMappers
mappedStatements
resultMaps
sqlFragments
interceptorChain # MyBatis攔截器調用鏈
interceptors # 攔截器集合,記錄了全部實現了Interceptor接口,而且使用了invocation變量的類
1 package org.apache.ibatis.plugin; 2 ... 3 4 public class Plugin implements InvocationHandler { 5 ... 6 7 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 8 try { 9 Set<Method> methods = signatureMap.get(method.getDeclaringClass()); 10 if (methods != null && methods.contains(method)) { 11 // 執行攔截器的邏輯 12 return interceptor.intercept(new Invocation(target, method, args)); 13 } 14 return method.invoke(target, args); 15 } catch (Exception e) { 16 throw ExceptionUtil.unwrapThrowable(e); 17 } 18 } 19 ... 20 }
1 package com.github.pagehelper; 2 ... 3 4 /** 5 * Mybatis - 通用分頁攔截器 6 */ 7 @SuppressWarnings("rawtypes") 8 @Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})) 9 public class PageHelper extends BasePageHelper implements Interceptor { 10 private final SqlUtil sqlUtil = new SqlUtil(); 11 12 @Override 13 public Object intercept(Invocation invocation) throws Throwable { 14 // 執行 sqlUtil 的攔截邏輯 15 return sqlUtil.intercept(invocation); 16 } 17 18 @Override 19 public Object plugin(Object target) { 20 return Plugin.wrap(target, this); 21 } 22 23 @Override 24 public void setProperties(Properties properties) { 25 sqlUtil.setProperties(properties); 26 } 27 }
1 package com.github.pagehelper.util; 2 ... 3 4 public class SqlUtil extends BaseSqlUtil implements Constant { 5 ... 6 7 /** 8 * 真正的攔截器方法 9 * 10 * @param invocation 11 * @return 12 * @throws Throwable 13 */ 14 public Object intercept(Invocation invocation) throws Throwable { 15 try { 16 return doIntercept(invocation); // 執行攔截 17 } finally { 18 clearLocalPage(); // 清空 ThreadLocal<Page> 19 } 20 } 21 22 /** 23 * 真正的攔截器方法 24 * 25 * @param invocation 26 * @return 27 * @throws Throwable 28 */ 29 public Object doIntercept(Invocation invocation) throws Throwable { 30 // 省略其餘代碼 31 32 // 調用方法判斷是否須要進行分頁 33 if (!runtimeDialect.skip(ms, parameterObject, rowBounds)) { 34 ResultHandler resultHandler = (ResultHandler) args[3]; 35 // 當前的目標對象 36 Executor executor = (Executor) invocation.getTarget(); 37 38 /** 39 * getBoundSql 方法執行後,boundSql 中保存的是沒有 limit 的sql語句 40 */ 41 BoundSql boundSql = ms.getBoundSql(parameterObject); 42 43 // 反射獲取動態參數 44 Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql); 45 // 判斷是否須要進行 count 查詢,默認須要 46 if (runtimeDialect.beforeCount(ms, parameterObject, rowBounds)) { 47 // 省略代碼 48 49 // 執行 count 查詢 50 Object countResultList = executor.query(countMs, parameterObject, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql); 51 Long count = (Long) ((List) countResultList).get(0); 52 53 // 處理查詢總數,從 ThreadLocal<Page> 中取出 page 並設置 total 54 runtimeDialect.afterCount(count, parameterObject, rowBounds); 55 if (count == 0L) { 56 // 當查詢總數爲 0 時,直接返回空的結果 57 return runtimeDialect.afterPage(new ArrayList(), parameterObject, rowBounds); 58 } 59 } 60 // 判斷是否須要進行分頁查詢 61 if (runtimeDialect.beforePage(ms, parameterObject, rowBounds)) { 62 /** 63 * 生成分頁的緩存 key 64 * pageKey變量是分頁參數存放的地方 65 */ 66 CacheKey pageKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql); 67 /** 68 * 處理參數對象,會從 ThreadLocal<Page> 中將分頁參數取出來,放入 pageKey 中 69 * 主要邏輯就是這樣,代碼就再也不單獨貼出來了,有興趣的同窗能夠跟進驗證 70 */ 71 parameterObject = runtimeDialect.processParameterObject(ms, parameterObject, boundSql, pageKey); 72 /** 73 * 調用方言獲取分頁 sql 74 * 該方法執行後,pageSql中保存的sql語句,被加上了 limit 語句 75 */ 76 String pageSql = runtimeDialect.getPageSql(ms, boundSql, parameterObject, rowBounds, pageKey); 77 BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameterObject); 78 //設置動態參數 79 for (String key : additionalParameters.keySet()) { 80 pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); 81 } 82 /** 83 * 執行分頁查詢 84 */ 85 resultList = executor.query(ms, parameterObject, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql); 86 } else { 87 resultList = new ArrayList(); 88 } 89 } else { 90 args[2] = RowBounds.DEFAULT; 91 // 不須要分頁查詢,執行原方法,不走代理 92 resultList = (List) invocation.proceed(); 93 } 94 /** 95 * 主要邏輯: 96 * 從 ThreadLocal<Page> 中取出 page 97 * 將 resultList 塞進 page,並返回 98 */ 99 return runtimeDialect.afterPage(resultList, parameterObject, rowBounds); 100 } 101 ... 102 }
創做時間:2019-11-20 21:21php