自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

手把手教你開發(fā) MyBatis 插件

開發(fā) 前端
在日常開發(fā)中,小伙伴們多多少少都有用過(guò) MyBatis 插件,松哥猜測(cè)大家用的最多的就是 MyBatis 的分頁(yè)插件!不知道小伙伴們有沒(méi)有想過(guò)有一天自己也來(lái)開發(fā)一個(gè) MyBatis 插件?

[[383827]]

 小伙伴們?cè)?jié)快樂(lè),記得吃元宵哦~

在日常開發(fā)中,小伙伴們多多少少都有用過(guò) MyBatis 插件,松哥猜測(cè)大家用的最多的就是 MyBatis 的分頁(yè)插件!不知道小伙伴們有沒(méi)有想過(guò)有一天自己也來(lái)開發(fā)一個(gè) MyBatis 插件?

其實(shí)自己動(dòng)手?jǐn)]一個(gè) MyBatis 插件并不難,今天松哥就把手帶大家擼一個(gè) MyBatis 插件!

1.MyBatis 插件接口

即使你沒(méi)開發(fā)過(guò) MyBatis 插件,估計(jì)也能猜出來(lái),MyBatis 插件是通過(guò)攔截器來(lái)起作用的,MyBatis 框架在設(shè)計(jì)的時(shí)候,就已經(jīng)為插件的開發(fā)預(yù)留了相關(guān)接口,如下:

  1. public interface Interceptor { 
  2.  
  3.   Object intercept(Invocation invocation) throws Throwable; 
  4.  
  5.   default Object plugin(Object target) { 
  6.     return Plugin.wrap(target, this); 
  7.   } 
  8.  
  9.   default void setProperties(Properties properties) { 
  10.     // NOP 
  11.   } 
  12.  

這個(gè)接口中就三個(gè)方法,第一個(gè)方法必須實(shí)現(xiàn),后面兩個(gè)方法都是可選的。三個(gè)方法作用分別如下:

  1. intercept:這個(gè)就是具體的攔截方法,我們自定義 MyBatis 插件時(shí),一般都需要重寫該方法,我們插件所完成的工作也都是在該方法中完成的。
  2. plugin:這個(gè)方法的參數(shù) target 就是攔截器要攔截的對(duì)象,一般來(lái)說(shuō)我們不需要重寫該方法。Plugin.wrap 方法會(huì)自動(dòng)判斷攔截器的簽名和被攔截對(duì)象的接口是否匹配,如果匹配,才會(huì)通過(guò)動(dòng)態(tài)代理攔截目標(biāo)對(duì)象。
  3. setProperties:這個(gè)方法用來(lái)傳遞插件的參數(shù),可以通過(guò)參數(shù)來(lái)改變插件的行為。我們定義好插件之后,需要對(duì)插件進(jìn)行配置,在配置的時(shí)候,可以給插件設(shè)置相關(guān)屬性,設(shè)置的屬性可以通過(guò)該方法獲取到。插件屬性設(shè)置像下面這樣:
  1. <plugins> 
  2.     <plugin interceptor="org.javaboy.mybatis03.plugin.CamelInterceptor"
  3.         <property name="xxx" value="xxx"/> 
  4.     </plugin> 
  5. </plugins> 

2.MyBatis 攔截器簽名

攔截器定義好了后,攔截誰(shuí)?

這個(gè)就需要攔截器簽名來(lái)完成了!

攔截器簽名是一個(gè)名為 @Intercepts 的注解,該注解中可以通過(guò) @Signature 配置多個(gè)簽名。@Signature 注解中則包含三個(gè)屬性:

  • type: 攔截器需要攔截的接口,有 4 個(gè)可選項(xiàng),分別是:Executor、ParameterHandler、ResultSetHandler 以及 StatementHandler。
  • method: 攔截器所攔截接口中的方法名,也就是前面四個(gè)接口中的方法名,接口和方法要對(duì)應(yīng)上。
  • args: 攔截器所攔截方法的參數(shù)類型,通過(guò)方法名和參數(shù)類型可以鎖定唯一一個(gè)方法。

一個(gè)簡(jiǎn)單的簽名可能像下面這樣:

  1. @Intercepts(@Signature( 
  2.         type = ResultSetHandler.class, 
  3.         method = "handleResultSets"
  4.         args = {Statement.class} 
  5. )) 
  6. public class CamelInterceptor implements Interceptor { 
  7.     //... 

3.被攔截的對(duì)象

根據(jù)前面的介紹,被攔截的對(duì)象主要有如下四個(gè):

Executor

  1. public interface Executor { 
  2.  
  3.   ResultHandler NO_RESULT_HANDLER = null
  4.  
  5.   int update(MappedStatement ms, Object parameter) throws SQLException; 
  6.  
  7.   <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; 
  8.  
  9.   <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException; 
  10.  
  11.   <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException; 
  12.  
  13.   List<BatchResult> flushStatements() throws SQLException; 
  14.  
  15.   void commit(boolean required) throws SQLException; 
  16.  
  17.   void rollback(boolean required) throws SQLException; 
  18.  
  19.   CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql); 
  20.  
  21.   boolean isCached(MappedStatement ms, CacheKey key); 
  22.  
  23.   void clearLocalCache(); 
  24.  
  25.   void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType); 
  26.  
  27.   Transaction getTransaction(); 
  28.  
  29.   void close(boolean forceRollback); 
  30.  
  31.   boolean isClosed(); 
  32.  
  33.   void setExecutorWrapper(Executor executor); 
  34.  

各方法含義分別如下:

  • update:該方法會(huì)在所有的 INSERT、 UPDATE、 DELETE 執(zhí)行時(shí)被調(diào)用,如果想要攔截這些操作,可以通過(guò)該方法實(shí)現(xiàn)。
  • query:該方法會(huì)在 SELECT 查詢方法執(zhí)行時(shí)被調(diào)用,方法參數(shù)攜帶了很多有用的信息,如果需要獲取,可以通過(guò)該方法實(shí)現(xiàn)。
  • queryCursor:當(dāng) SELECT 的返回類型是 Cursor 時(shí),該方法會(huì)被調(diào)用。
  • flushStatements:當(dāng) SqlSession 方法調(diào)用 flushStatements 方法或執(zhí)行的接口方法中帶有 @Flush 注解時(shí)該方法會(huì)被觸發(fā)。
  • commit:當(dāng) SqlSession 方法調(diào)用 commit 方法時(shí)該方法會(huì)被觸發(fā)。
  • rollback:當(dāng) SqlSession 方法調(diào)用 rollback 方法時(shí)該方法會(huì)被觸發(fā)。
  • getTransaction:當(dāng) SqlSession 方法獲取數(shù)據(jù)庫(kù)連接時(shí)該方法會(huì)被觸發(fā)。
  • close:該方法在懶加載獲取新的 Executor 后會(huì)被觸發(fā)。
  • isClosed:該方法在懶加載執(zhí)行查詢前會(huì)被觸發(fā)。

ParameterHandler

  1. public interface ParameterHandler { 
  2.  
  3.   Object getParameterObject(); 
  4.  
  5.   void setParameters(PreparedStatement ps) throws SQLException; 
  6.  

各方法含義分別如下:

  • getParameterObject:在執(zhí)行存儲(chǔ)過(guò)程處理出參的時(shí)候該方法會(huì)被觸發(fā)。
  • setParameters:設(shè)置 SQL 參數(shù)時(shí)該方法會(huì)被觸發(fā)。

ResultSetHandler

  1. public interface ResultSetHandler { 
  2.  
  3.   <E> List<E> handleResultSets(Statement stmt) throws SQLException; 
  4.  
  5.   <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException; 
  6.  
  7.   void handleOutputParameters(CallableStatement cs) throws SQLException; 
  8.  

各方法含義分別如下:

  • handleResultSets:該方法會(huì)在所有的查詢方法中被觸發(fā)(除去返回值類型為 Cursor的查詢方法),一般來(lái)說(shuō),如果我們想對(duì)查詢結(jié)果進(jìn)行二次處理,可以通過(guò)攔截該方法實(shí)現(xiàn)。
  • handleCursorResultSets:當(dāng)查詢方法的返回值類型為 Cursor時(shí),該方法會(huì)被觸發(fā)。
  • handleOutputParameters:使用存儲(chǔ)過(guò)程處理出參的時(shí)候該方法會(huì)被調(diào)用。

StatementHandler

  1. public interface StatementHandler { 
  2.  
  3.   Statement prepare(Connection connectionInteger transactionTimeout) 
  4.       throws SQLException; 
  5.  
  6.   void parameterize(Statement statement) 
  7.       throws SQLException; 
  8.  
  9.   void batch(Statement statement) 
  10.       throws SQLException; 
  11.  
  12.   int update(Statement statement) 
  13.       throws SQLException; 
  14.  
  15.   <E> List<E> query(Statement statement, ResultHandler resultHandler) 
  16.       throws SQLException; 
  17.  
  18.   <E> Cursor<E> queryCursor(Statement statement) 
  19.       throws SQLException; 
  20.  
  21.   BoundSql getBoundSql(); 
  22.  
  23.   ParameterHandler getParameterHandler(); 
  24.  

各方法含義分別如下:

  • prepare:該方法在數(shù)據(jù)庫(kù)執(zhí)行前被觸發(fā)。
  • parameterize:該方法在 prepare 方法之后執(zhí)行,用來(lái)處理參數(shù)信息。
  • batch:如果 MyBatis 的全劇配置中配置了 defaultExecutorType=”BATCH”,執(zhí)行數(shù)據(jù)操作時(shí)該方法會(huì)被調(diào)用。
  • update:更新操作時(shí)該方法會(huì)被觸發(fā)。
  • query:該方法在 SELECT 方法執(zhí)行時(shí)會(huì)被觸發(fā)。
  • queryCursor:該方法在 SELECT 方法執(zhí)行時(shí),并且返回值為 Cursor 時(shí)會(huì)被觸發(fā)。

在開發(fā)一個(gè)具體的插件時(shí),我們應(yīng)當(dāng)根據(jù)自己的需求來(lái)決定到底攔截哪個(gè)方法。

4.開發(fā)分頁(yè)插件

4.1 內(nèi)存分頁(yè)

MyBatis 中提供了一個(gè)不太好用的內(nèi)存分頁(yè)功能,就是一次性把所有數(shù)據(jù)都查詢出來(lái),然后在內(nèi)存中進(jìn)行分頁(yè)處理,這種分頁(yè)方式效率很低,基本上沒(méi)啥用,但是如果我們想要自定義分頁(yè)插件,就需要對(duì)這種分頁(yè)方式有一個(gè)簡(jiǎn)單了解。

內(nèi)存分頁(yè)的使用方式如下,首先在 Mapper 中添加 RowBounds 參數(shù),如下:

  1. public interface UserMapper { 
  2.     List<User> getAllUsersByPage(RowBounds rowBounds); 

然后在 XML 文件中定義相關(guān) SQL:

  1. <select id="getAllUsersByPage" resultType="org.javaboy.mybatis03.model.User"
  2.     select * from user 
  3. </select

可以看到,在 SQL 定義時(shí),壓根不用管分頁(yè)的事情,MyBatis 會(huì)查詢到所有的數(shù)據(jù),然后在內(nèi)存中進(jìn)行分頁(yè)處理。

Mapper 中方法的調(diào)用方式如下:

  1. @Test 
  2. public void test3() { 
  3.     UserMapper userMapper = sqlSessionFactory.openSession().getMapper(UserMapper.class); 
  4.     RowBounds rowBounds = new RowBounds(1,2); 
  5.     List<User> list = userMapper.getAllUsersByPage(rowBounds); 
  6.     for (User user : list) { 
  7.         System.out.println("user = " + user); 
  8.     } 

構(gòu)建 RowBounds 時(shí)傳入兩個(gè)參數(shù),分別是 offset 和 limit,對(duì)應(yīng)分頁(yè) SQL 中的兩個(gè)參數(shù)。也可以通過(guò) RowBounds.DEFAULT 的方式構(gòu)建一個(gè) RowBounds 實(shí)例,這種方式構(gòu)建出來(lái)的 RowBounds 實(shí)例,offset 為 0,limit 則為 Integer.MAX_VALUE,也就相當(dāng)于不分頁(yè)。

這就是 MyBatis 中提供的一個(gè)很不實(shí)用的內(nèi)存分頁(yè)功能。

了解了 MyBatis 自帶的內(nèi)存分頁(yè)之后,接下來(lái)我們就可以來(lái)看看如何自定義分頁(yè)插件了。

4.2 自定義分頁(yè)插件

首先要聲明一下,這里松哥帶大家自定義 MyBatis 分頁(yè)插件,主要是想通過(guò)這個(gè)東西讓小伙伴們了解自定義 MyBatis 插件的一些條條框框,了解整個(gè)自定義插件的流程,分頁(yè)插件并不是我們的目的,自定義分頁(yè)插件只是為了讓大家的學(xué)習(xí)過(guò)程變得有趣一些而已。

接下來(lái)我們就來(lái)開啟自定義分頁(yè)插件之旅。

首先我們需要自定義一個(gè) RowBounds,因?yàn)?MyBatis 原生的 RowBounds 是內(nèi)存分頁(yè),并且沒(méi)有辦法獲取到總記錄數(shù)(一般分頁(yè)查詢的時(shí)候我們還需要獲取到總記錄數(shù)),所以我們自定義 PageRowBounds,對(duì)原生的 RowBounds 功能進(jìn)行增強(qiáng),如下:

  1. public class PageRowBounds extends RowBounds { 
  2.     private Long total; 
  3.  
  4.     public PageRowBounds(int offset, int limit) { 
  5.         super(offset, limit); 
  6.     } 
  7.  
  8.     public PageRowBounds() { 
  9.     } 
  10.  
  11.     public Long getTotal() { 
  12.         return total; 
  13.     } 
  14.  
  15.     public void setTotal(Long total) { 
  16.         this.total = total; 
  17.     } 

可以看到,我們自定義的 PageRowBounds 中增加了 total 字段,用來(lái)保存查詢的總記錄數(shù)。

接下來(lái)我們自定義攔截器 PageInterceptor,如下:

  1. @Intercepts(@Signature( 
  2.         type = Executor.class, 
  3.         method = "query"
  4.         args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} 
  5. )) 
  6. public class PageInterceptor implements Interceptor { 
  7.     @Override 
  8.     public Object intercept(Invocation invocation) throws Throwable { 
  9.         Object[] args = invocation.getArgs(); 
  10.         MappedStatement ms = (MappedStatement) args[0]; 
  11.         Object parameterObject = args[1]; 
  12.         RowBounds rowBounds = (RowBounds) args[2]; 
  13.         if (rowBounds != RowBounds.DEFAULT) { 
  14.             Executor executor = (Executor) invocation.getTarget(); 
  15.             BoundSql boundSql = ms.getBoundSql(parameterObject); 
  16.             Field additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters"); 
  17.             additionalParametersField.setAccessible(true); 
  18.             Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql); 
  19.             if (rowBounds instanceof PageRowBounds) { 
  20.                 MappedStatement countMs = newMappedStatement(ms, Long.class); 
  21.                 CacheKey countKey = executor.createCacheKey(countMs, parameterObject, RowBounds.DEFAULT, boundSql); 
  22.                 String countSql = "select count(*) from (" + boundSql.getSql() + ") temp"
  23.                 BoundSql countBoundSql = new BoundSql(ms.getConfiguration(), countSql, boundSql.getParameterMappings(), parameterObject); 
  24.                 Set<String> keySet = additionalParameters.keySet(); 
  25.                 for (String key : keySet) { 
  26.                     countBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); 
  27.                 } 
  28.                 List<Object> countQueryResult = executor.query(countMs, parameterObject, RowBounds.DEFAULT, (ResultHandler) args[3], countKey, countBoundSql); 
  29.                 Long count = (Long) countQueryResult.get(0); 
  30.                 ((PageRowBounds) rowBounds).setTotal(count); 
  31.             } 
  32.             CacheKey pageKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql); 
  33.             pageKey.update("RowBounds"); 
  34.             String pageSql = boundSql.getSql() + " limit " + rowBounds.getOffset() + "," + rowBounds.getLimit(); 
  35.             BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameterObject); 
  36.             Set<String> keySet = additionalParameters.keySet(); 
  37.             for (String key : keySet) { 
  38.                 pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); 
  39.             } 
  40.             List list = executor.query(ms, parameterObject, RowBounds.DEFAULT, (ResultHandler) args[3], pageKey, pageBoundSql); 
  41.             return list; 
  42.         } 
  43.         //不需要分頁(yè),直接返回結(jié)果 
  44.         return invocation.proceed(); 
  45.     } 
  46.  
  47.     private MappedStatement newMappedStatement(MappedStatement ms, Class<Long> longClass) { 
  48.         MappedStatement.Builder builder = new MappedStatement.Builder( 
  49.                 ms.getConfiguration(), ms.getId() + "_count", ms.getSqlSource(), ms.getSqlCommandType() 
  50.         ); 
  51.         ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), longClass, new ArrayList<>(0)).build(); 
  52.         builder.resource(ms.getResource()) 
  53.                 .fetchSize(ms.getFetchSize()) 
  54.                 .statementType(ms.getStatementType()) 
  55.                 .timeout(ms.getTimeout()) 
  56.                 .parameterMap(ms.getParameterMap()) 
  57.                 .resultSetType(ms.getResultSetType()) 
  58.                 .cache(ms.getCache()) 
  59.                 .flushCacheRequired(ms.isFlushCacheRequired()) 
  60.                 .useCache(ms.isUseCache()) 
  61.                 .resultMaps(Arrays.asList(resultMap)); 
  62.         if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) { 
  63.             StringBuilder keyProperties = new StringBuilder(); 
  64.             for (String keyProperty : ms.getKeyProperties()) { 
  65.                 keyProperties.append(keyProperty).append(","); 
  66.             } 
  67.             keyProperties.delete(keyProperties.length() - 1, keyProperties.length()); 
  68.             builder.keyProperty(keyProperties.toString()); 
  69.         } 
  70.         return builder.build(); 
  71.     } 

這是我們今天定義的核心代碼,涉及到的知識(shí)點(diǎn)松哥來(lái)給大家一個(gè)一個(gè)剖析。

  1. 首先通過(guò) @Intercepts 注解配置攔截器簽名,從 @Signature 的定義中我們可以看到,攔截的是 Executor#query 方法,該方法有一個(gè)重載方法,通過(guò) args 指定了方法參數(shù),進(jìn)而鎖定了重載方法(實(shí)際上該方法的另一個(gè)重載方法我們沒(méi)法攔截,那個(gè)是 MyBatis 內(nèi)部調(diào)用的,這里不做討論)。
  2. 將查詢操作攔截下來(lái)之后,接下來(lái)我們的操作主要在 PageInterceptor#intercept 方法中完成,該方法的參數(shù)重包含了攔截對(duì)象的諸多信息。
  3. 通過(guò) invocation.getArgs() 獲取攔截方法的參數(shù),獲取到的是一個(gè)數(shù)組,正常來(lái)說(shuō)這個(gè)數(shù)組的長(zhǎng)度為 4。數(shù)組第一項(xiàng)是一個(gè) MappedStatement,我們?cè)?Mapper.xml 中定義的各種操作節(jié)點(diǎn)和 SQL,都被封裝成一個(gè)個(gè)的 MappedStatement 對(duì)象了;數(shù)組第二項(xiàng)就是所攔截方法的具體參數(shù),也就是你在 Mapper 接口中定義的方法參數(shù);數(shù)組的第三項(xiàng)是一個(gè) RowBounds 對(duì)象,我們?cè)?Mapper 接口中定義方法時(shí)不一定使用了 RowBounds 對(duì)象,如果我們沒(méi)有定義 RowBounds 對(duì)象,系統(tǒng)會(huì)給我們提供一個(gè)默認(rèn)的 RowBounds.DEFAULT;數(shù)組第四項(xiàng)則是一個(gè)處理返回值的 ResultHandler。
  4. 接下來(lái)判斷上一步提取到的 rowBounds 對(duì)象是否不為 RowBounds.DEFAULT,如果為 RowBounds.DEFAULT,說(shuō)明用戶不想分頁(yè);如果不為 RowBounds.DEFAULT,則說(shuō)明用戶想要分頁(yè),如果用戶不想分頁(yè),則直接執(zhí)行最后的 return invocation.proceed();,讓方法繼續(xù)往下走就行了。
  5. 如果需要進(jìn)行分頁(yè),則先從 invocation 對(duì)象中取出執(zhí)行器 Executor、BoundSql 以及通過(guò)反射拿出來(lái) BoundSql 中保存的額外參數(shù)(如果我們使用了動(dòng)態(tài) SQL,可能會(huì)存在該參數(shù))。BoundSql 中封裝了我們執(zhí)行的 Sql 以及相關(guān)的參數(shù)。
  6. 接下來(lái)判斷 rowBounds 是否是 PageRowBounds 的實(shí)例,如果是,說(shuō)明除了分頁(yè)查詢,還想要查詢總記錄數(shù),如果不是,則說(shuō)明 rowBounds 可能是 RowBounds 實(shí)例,此時(shí)只要分頁(yè)即可,不用查詢總記錄數(shù)。
  7. 如果需要查詢總記錄數(shù),則首先調(diào)用 newMappedStatement 方法構(gòu)造出一個(gè)新的 MappedStatement 對(duì)象出來(lái),這個(gè)新的 MappedStatement 對(duì)象的返回值是 Long 類型的。然后分別創(chuàng)建查詢的 CacheKey、拼接查詢的 countSql,再根據(jù) countSql 構(gòu)建出 countBoundSql,再將額外參數(shù)添加進(jìn) countBoundSql 中。最后通過(guò) executor.query 方法完成查詢操作,并將查詢結(jié)果賦值給 PageRowBounds 中的 total 屬性。
  8. 接下來(lái)進(jìn)行分頁(yè)查詢,有了第七步的介紹之后,分頁(yè)查詢就很簡(jiǎn)單了,這里就不細(xì)說(shuō)了,唯一需要強(qiáng)調(diào)的是,當(dāng)我們啟動(dòng)了這個(gè)分頁(yè)插件之后,MyBatis 原生的 RowBounds 內(nèi)存分頁(yè)會(huì)變成物理分頁(yè),原因就在這里我們修改了查詢 SQL。
  9. 最后將查詢結(jié)果返回。

在前面的代碼中,我們一共在兩個(gè)地方重新組織了 SQL,一個(gè)是查詢總記錄數(shù)的時(shí)候,另一個(gè)則是分頁(yè)的時(shí)候,都是通過(guò) boundSql.getSql() 獲取到 Mapper.xml 中的 SQL 然后進(jìn)行改裝,有的小伙伴在 Mapper.xml 中寫 SQL 的時(shí)候不注意,結(jié)尾可能加上了 ;,這會(huì)導(dǎo)致分頁(yè)插件重新組裝的 SQL 運(yùn)行出錯(cuò),這點(diǎn)需要注意。松哥在 GitHub 上看到的其他 MyBatis 分頁(yè)插件也是一樣的,Mapper.xml 中 SQL 結(jié)尾不能有 ;。

如此之后,我們的分頁(yè)插件就算是定義成功了。

5.測(cè)試

接下來(lái)我們對(duì)我們的分頁(yè)插件進(jìn)行一個(gè)簡(jiǎn)單測(cè)試。

首先我們需要在全局配置中配置分頁(yè)插件,配置方式如下:

  1. <plugins> 
  2.     <plugin interceptor="org.javaboy.mybatis03.plugin.PageInterceptor"></plugin> 
  3. </plugins> 

接下來(lái)我們?cè)?Mapper 中定義查詢接口:

  1. public interface UserMapper { 
  2.     List<User> getAllUsersByPage(RowBounds rowBounds); 

接下來(lái)定義 UserMapper.xml,如下:

  1. <select id="getAllUsersByPage" resultType="org.javaboy.mybatis03.model.User"
  2.     select * from user 
  3. </select

最后我們進(jìn)行測(cè)試:

  1. @Test 
  2. public void test3() { 
  3.     UserMapper userMapper = sqlSessionFactory.openSession().getMapper(UserMapper.class); 
  4.     List<User> list = userMapper.getAllUsersByPage(new RowBounds(1,2)); 
  5.     for (User user : list) { 
  6.         System.out.println("user = " + user); 
  7.     } 

這里在查詢時(shí),我們使用了 RowBounds 對(duì)象,就只會(huì)進(jìn)行分頁(yè),而不會(huì)統(tǒng)計(jì)總記錄數(shù)。需要注意的時(shí),此時(shí)的分頁(yè)已經(jīng)不是內(nèi)存分頁(yè),而是物理分頁(yè)了,這點(diǎn)我們從打印出來(lái)的 SQL 中也能看到,如下:

 

可以看到,查詢的時(shí)候就已經(jīng)進(jìn)行了分頁(yè)了。

當(dāng)然,我們也可以使用 PageRowBounds 進(jìn)行測(cè)試,如下:

  1. @Test 
  2. public void test4() { 
  3.     UserMapper userMapper = sqlSessionFactory.openSession().getMapper(UserMapper.class); 
  4.     PageRowBounds pageRowBounds = new PageRowBounds(1, 2); 
  5.     List<User> list = userMapper.getAllUsersByPage(pageRowBounds); 
  6.     for (User user : list) { 
  7.         System.out.println("user = " + user); 
  8.     } 
  9.     System.out.println("pageRowBounds.getTotal() = " + pageRowBounds.getTotal()); 

此時(shí)通過(guò) pageRowBounds.getTotal() 方法我們就可以獲取到總記錄數(shù)。

6.小結(jié)

好啦,今天主要和小伙伴們分享了我們?nèi)绾巫约洪_發(fā)一個(gè) MyBatis 插件,插件功能其實(shí)都是次要的,最主要是希望小伙伴們能夠理解 MyBatis 的工作流程。

本文轉(zhuǎn)載自微信公眾號(hào)「江南一點(diǎn)雨」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系江南一點(diǎn)雨公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2024-04-02 08:58:13

2024-03-05 18:27:43

2024-03-18 18:07:38

VSCode插件文件

2011-04-28 15:09:15

jQueryjqPlot

2011-05-27 08:41:26

JavascriptFirefox

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印機(jī)

2021-07-14 09:00:00

JavaFX開發(fā)應(yīng)用

2011-03-28 16:14:38

jQuery

2011-02-22 13:46:27

微軟SQL.NET

2021-12-28 08:38:26

Linux 中斷喚醒系統(tǒng)Linux 系統(tǒng)

2022-01-08 20:04:20

攔截系統(tǒng)調(diào)用

2023-04-26 12:46:43

DockerSpringKubernetes

2022-12-07 08:42:35

2022-07-27 08:16:22

搜索引擎Lucene

2022-03-14 14:47:21

HarmonyOS操作系統(tǒng)鴻蒙

2021-11-24 16:02:57

鴻蒙HarmonyOS應(yīng)用

2009-06-02 15:38:36

eclipse streclipse開發(fā)steclipse str

2020-04-14 10:20:12

MySQL數(shù)據(jù)庫(kù)死鎖

2016-04-27 09:49:16

用戶模型產(chǎn)品總結(jié)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)