跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 支持连表等复杂查询的PageHelper——PageHelper5.1.4 Mybatis3.4.6 – VPS资讯
未分類
5 2 月 2020

支持连表等复杂查询的PageHelper——PageHelper5.1.4 Mybatis3.4.6 – VPS资讯


一、PageHelper中分页存在的问题:

  • 主表结构如下:
    provider_order表,订单主表。我们这里简化处理,它只有一个字段,即id。

VARCHAR  |  po_id   |    订单表id

  • 从表结构如下:
    order_info表,订单从表。它负责记录订单的一些信息,与主表是一对多的关系。

VARCHAR  |  oi_id  |  订单信息id VARCHAR  |  po_id   |    订单表id TEXT    |  info   |   信息详情

  • 现在我们需要一个简单的连表查询操作,sql语句如下:
<select id="getProviderOrderWithOrderInfoTest" resultMap="ResultMapWithOrderInfo" parameterType="java.lang.String">         SELECT *         FROM (SELECT * FROM provider_order WHERE po_id LIKE #{po_id}) AS limitable             LEFT JOIN order_info ON limitable.po_id = order_info.provider_order_id     </select>
  • 进行PageHelper的分页操作,查询前十条记录:
 Page page = PageHelper.startPage(0, 10);         List<ProviderOrder> providerOrderList = testService.getProviderOrderWithOrderInfoTest("%-%");         PageInfo<ProviderOrder> pageInfo = new PageInfo<>(providerOrderList);          System.out.println(pageInfo); 
  • 目前我们的主表有两条记录,从表有二十条记录。

我们会发现,查询出来的总数是20,然后查询结果是两个list(各5条从表信息),不仅如此,分页数据也很奇怪,我们只有两条主表记录,但却被分成了两页(pages = 2),并且hasNextPage = true。这并不是我们要的结果。我们想要查询的效果是:

前十条 订单 记录,然后连表查询出该十条订单记录下的所有 订单信息
也就是说,结果集中,首先我们应该得到两个list,list中各10条从表信息,而且也不该有下一页,总页数应为1,总数据数应为2。

查看PageHelper的源码我们来看看,它的count,以及limit,到底是怎么回事。

PageHelper的count实现

 private Long executeAutoCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, RowBounds rowBounds, ResultHandler resultHandler) throws IllegalAccessException,         SQLException {         Map<String, Object> additionalParameters = (Map) this.additionalParametersField.get(boundSql);         CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);         String countSql = this.dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey);         BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter);         Iterator var11 = additionalParameters.keySet()                                              .iterator();          while (var11.hasNext()) {             String key = (String) var11.next();             countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));         }          Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);         Long count = (Long) ((List) countResultList).get(0);          // 获取count         return count;     }

我们很容易看出来,count的sql语句,在这里经过了处理,这里调用了dialect的getCountSql方法。 它的实现如下:

 public String getSmartCountSql(String sql, String name) {         Statement stmt = null;         if (sql.indexOf("/*keep orderby*/") >= 0) {             return this.getSimpleCountSql(sql);         } else {             try {                 stmt = CCJSqlParserUtil.parse(sql);             } catch (Throwable var8) {                 return this.getSimpleCountSql(sql);             }              Select select = (Select)stmt;             SelectBody selectBody = select.getSelectBody();              try {                 this.processSelectBody(selectBody);             } catch (Exception var7) {                 return this.getSimpleCountSql(sql);             }              this.processWithItemsList(select.getWithItemsList());             this.sqlToCount(select, name);             String result = select.toString();             return result;         }     }      public String getSimpleCountSql(String sql) {         return this.getSimpleCountSql(sql, "0");     }      public String getSimpleCountSql(String sql, String name) {         StringBuilder stringBuilder = new StringBuilder(sql.length() + 40);         stringBuilder.append("select count(");         stringBuilder.append(name);         stringBuilder.append(") from (");         stringBuilder.append(sql);         stringBuilder.append(") tmp_count");         return stringBuilder.toString();     }

简单来说,就是在sql外面套一层select count语句,我们的sql语句变成了 SELECT count(0) FROM (我们的sql语句)(真实情况没有这么简单,这只是其中一种情况。)这样就很容易得知,为什么最后的total是20(所有数据数),而不是2(主表数据数)了。

三、 PageHelper的分页实现

与上面相同,这里以dialect(为了适配各种数据库)为mysql为例,我们可以看到,如果你没有在sql语句里面写limit,就会在sql语句的最后面,添加limit语句。

public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {         StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);         sqlBuilder.append(sql);         if (rowBounds.getOffset() == 0) {             sqlBuilder.append(" LIMIT ");             sqlBuilder.append(rowBounds.getLimit());         } else {             sqlBuilder.append(" LIMIT ");             sqlBuilder.append(rowBounds.getOffset());             sqlBuilder.append(",");             sqlBuilder.append(rowBounds.getLimit());             pageKey.update(rowBounds.getOffset());         }          pageKey.update(rowBounds.getLimit());         return sqlBuilder.toString();     }

程序运行得到sql语句如下,PageHelper对查询的总结果集(包括主表数据与从表数据),进行了分页

在得知PageHelper在这两个步骤的原理后,我们开始对PageHelper进行改造。

四、 count结果修正

在上面的count源码中,我们可以看到这么一段代码:

  public String getSmartCountSql(String sql, String name) {         Statement stmt = null;         if (sql.indexOf("/*keep orderby*/") >= 0) {             return this.getSimpleCountSql(sql);         } else {             try {                 stmt = CCJSqlParserUtil.parse(sql);             } catch (Throwable var8) {                 return this.getSimpleCountSql(sql);             }              Select select = (Select)stmt;             SelectBody selectBody = select.getSelectBody();              try {                 this.processSelectBody(selectBody);             } catch (Exception var7) {                 return this.getSimpleCountSql(sql);             }              this.processWithItemsList(select.getWithItemsList());             this.sqlToCount(select, name);             String result = select.toString();             return result;         }     }       public void sqlToCount(Select select, String name) {         SelectBody selectBody = select.getSelectBody();         List<SelectItem> COUNT_ITEM = new ArrayList();         COUNT_ITEM.add(new SelectExpressionItem(new Column("count(" + name + ")")));         if (selectBody instanceof PlainSelect && this.isSimpleCount((PlainSelect)selectBody)) {             ((PlainSelect)selectBody).setSelectItems(COUNT_ITEM);         } else {             PlainSelect plainSelect = new PlainSelect();             SubSelect subSelect = new SubSelect();             subSelect.setSelectBody(selectBody);             subSelect.setAlias(TABLE_ALIAS);             plainSelect.setFromItem(subSelect);             plainSelect.setSelectItems(COUNT_ITEM);             select.setSelectBody(plainSelect);         }      }

实际上PageHelper是有提供给我们一套指定colum查询的入口的。我们将查询代码做如下改造:

   Page page = PageHelper.startPage(0, 10);         page.setCountColumn("DISTINCT po_id");         List<ProviderOrder> providerOrderList = testService.getProviderOrderWithOrderInfoTest("%-%");          PageInfo<ProviderOrder> pageInfo = new PageInfo<>(providerOrderList);          System.out.println(pageInfo); 

我们会发现,我们需要的分页数据正常了,总页码(pages:1),total:2。

五、 查询结果集修正

我们在三中,发现了PageHelper limit添加的位置不正确,我们需要将其放在正确的位置下。所以新建一个类如下:

/**  * Created by Anur IjuoKaruKas on 2018/6/8  */ public class PageSqlResolver {      public static final String SQL_SIGN = "AS limitable";      public static final String LIMIT_SIGN = "LIMIT ?";      public static final String LIMIT_SIGN_EX = "LIMIT ?, ?";      public static String resolveLimit(String pageSql) {         if (pageSql == null) {             return null;         }          if (pageSql.contains(SQL_SIGN)) {// 如果需要特殊分页             String changer = "";              if (pageSql.contains(LIMIT_SIGN_EX)) {                 changer = LIMIT_SIGN_EX;             } else if (pageSql.contains(LIMIT_SIGN)) {                 changer = LIMIT_SIGN;             }              pageSql = pageSql.replace(changer, "");             StringBuilder sqlBuilder = new StringBuilder(pageSql);              StringBuilder mae = new StringBuilder(sqlBuilder.substring(0, sqlBuilder.indexOf(SQL_SIGN)));// mae 截止sql语句到 limitable             StringBuilder uShiRo = new StringBuilder(sqlBuilder.substring(sqlBuilder.indexOf(SQL_SIGN), sqlBuilder.length()));// 剩余的              mae.insert(mae.lastIndexOf(")"), String.format(" %s", changer));              return mae.append(uShiRo)                       .toString();         } else {             return pageSql;         }     } }

这段代码的含义是:将AS limitable,也就是主表,标记为真正分页的地方,并向其添如limit ? ,?

SELECT *         FROM (SELECT * FROM provider_order WHERE po_id LIKE ?) AS limitable             LEFT JOIN order_info ON limitable.po_id = order_info.provider_order_id LIMIT ? 

sql语句从上面变成了:

SELECT *         FROM (SELECT * FROM provider_order WHERE po_id LIKE ? LIMIT ?) AS limitable             LEFT JOIN order_info ON limitable.po_id = order_info.provider_order_id   

我们发现这就是我们想要的结果,它的分页是针对主表进行的,而不是针对结果集。

解析到这里就结束了
https://github.com/anurnomeru/page-helper-ext demo示例请点击这里

六、改造步骤详解

1、引入依赖 这里使用了mybatis 3.4.6(tk.mybatis 4.0.2),pagehelper5.1.4(pagehelper-spring-boot-starter1.2.5),你可以引入原依赖,也可以用这里使用的tkMybatis,以及pagehelper-spring-boot-starter。

 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>      <groupId>com.anur</groupId>     <artifactId>page-helper</artifactId>     <version>0.0.1-SNAPSHOT</version>     <packaging>jar</packaging>      <name>page-helper</name>     <description>Demo project for Spring Boot</description>      <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.0.2.RELEASE</version>         <relativePath/> <!-- lookup parent from repository -->     </parent>      <properties>         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>         <java.version>1.8</java.version>     </properties>      <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>          <!-- page - helper -->         <dependency>             <groupId>com.github.pagehelper</groupId>             <artifactId>pagehelper-spring-boot-starter</artifactId>             <version>1.2.5</version>         </dependency>          <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <optional>true</optional>         </dependency>          <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-test</artifactId>             <scope>test</scope>         </dependency>          <!-- codeGen -->         <dependency>             <groupId>org.mybatis.generator</groupId>             <artifactId>mybatis-generator-core</artifactId>             <version>1.3.6</version>         </dependency>          <!-- tk - mybatis -->         <dependency>             <groupId>tk.mybatis</groupId>             <artifactId>mapper</artifactId>             <version>4.0.2</version>         </dependency>          <!-- mysql -->         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>             <scope>runtime</scope>         </dependency>          <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->         <dependency>             <groupId>com.alibaba</groupId>             <artifactId>fastjson</artifactId>             <version>1.2.47</version>         </dependency>      </dependencies>      <build>         <plugins>             <plugin>                 <groupId>org.springframework.boot</groupId>                 <artifactId>spring-boot-maven-plugin</artifactId>             </plugin>             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-compiler-plugin</artifactId>                 <configuration>                     <proc>none</proc>                 </configuration>             </plugin>         </plugins>     </build>   </project>  

2、新增两个类,用于修正查询时sql语句

package com.anur.pagehelper.page;  // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) //  import com.github.pagehelper.Dialect; import com.github.pagehelper.PageException; import com.github.pagehelper.cache.Cache; import com.github.pagehelper.cache.CacheFactory; import com.github.pagehelper.util.MSUtils; import com.github.pagehelper.util.StringUtil; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds;  /**  * Created by Anur IjuoKaruKas on 2018/6/8  */  @Intercepts({     @Signature(         type = Executor.class,         method = "query",         args = {             MappedStatement.class,             Object.class,             RowBounds.class,             ResultHandler.class         }     ),     @Signature(         type = Executor.class,         method = "query",         args = {             MappedStatement.class,             Object.class,             RowBounds.class,             ResultHandler.class,             CacheKey.class,             BoundSql.class         }     ) }) public class CustomPageInterceptor implements Interceptor {      protected Cache<String, MappedStatement> msCountMap = null;      private Dialect dialect;      private String default_dialect_class = "com.github.pagehelper.PageHelper";      private Field additionalParametersField;      private String countSuffix = "_COUNT";      public CustomPageInterceptor() {     }      /**      * 拦截      */     public Object intercept(Invocation invocation) throws Throwable {         try {             Object[] args = invocation.getArgs();              // 对应一个Mapper节点,描述一条sql语句             MappedStatement ms = (MappedStatement) args[0];              // 参数             Object parameter = args[1];              // mybatis自带分页             RowBounds rowBounds = (RowBounds) args[2];              // 结果集处理器             ResultHandler resultHandler = (ResultHandler) args[3];              // 执行器             Executor executor = (Executor) invocation.getTarget();             CacheKey cacheKey;             BoundSql boundSql;              if (args.length == 4) {                 boundSql = ms.getBoundSql(parameter);                 cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);             } else {                 cacheKey = (CacheKey) args[4];                 boundSql = (BoundSql) args[5];             }              List resultList;             if (this.dialect.skip(ms, parameter, rowBounds)) {                 resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);             } else {                 String msId = ms.getId();                 Configuration configuration = ms.getConfiguration();                 Map<String, Object> additionalParameters = (Map) this.additionalParametersField.get(boundSql);                 if (this.dialect.beforeCount(ms, parameter, rowBounds)) {                     String countMsId = msId + this.countSuffix;                     MappedStatement countMs = this.getExistedMappedStatement(configuration, countMsId);                     Long count;                     if (countMs != null) {                         count = this.executeManualCount(executor, countMs, parameter, boundSql, resultHandler);                     } else {                         countMs = (MappedStatement) this.msCountMap.get(countMsId);                         if (countMs == null) {                             countMs = MSUtils.newCountMappedStatement(ms, countMsId);                             this.msCountMap.put(countMsId, countMs);                         }                          // 这里是count,可能要改 //                        boundSql = PageSqlResolver.resolveCount(configuration, boundSql, parameter);                         count = this.executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);                     }                      if (!this.dialect.afterCount(count, parameter, rowBounds)) {                         Object var24 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds);                         return var24;                     }                 }                  if (!this.dialect.beforePage(ms, parameter, rowBounds)) {                     resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);                 } else {                     parameter = this.dialect.processParameterObject(ms, parameter, boundSql, cacheKey);                     String pageSql = this.dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey);                      // 对sql进行改造                     pageSql = PageSqlResolver.resolveLimit(pageSql);                      BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter);                     Iterator var17 = additionalParameters.keySet()                                                          .iterator();                      while (true) {                         if (!var17.hasNext()) {                             resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, pageBoundSql);                             break;                         }                          String key = (String) var17.next();                         pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));                     }                 }             }              Object var22 = this.dialect.afterPage(resultList, parameter, rowBounds);             return var22;         } finally {             this.dialect.afterAll();         }     }      private Long executeManualCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, ResultHandler resultHandler) throws IllegalAccessException, SQLException {         CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);         BoundSql countBoundSql = countMs.getBoundSql(parameter);         Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);         Long count = ((Number) ((List) countResultList).get(0)).longValue();         return count;     }      private Long executeAutoCount(Executor executor, MappedStatement countMs, Object parameter, BoundSql boundSql, RowBounds rowBounds, ResultHandler resultHandler) throws IllegalAccessException,         SQLException {         Map<String, Object> additionalParameters = (Map) this.additionalParametersField.get(boundSql);         CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);         String countSql = this.dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey);         BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter);         Iterator var11 = additionalParameters.keySet()                                              .iterator();          while (var11.hasNext()) {             String key = (String) var11.next();             countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));         }          Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);         Long count = (Long) ((List) countResultList).get(0);          // 获取count         return count;     }      private MappedStatement getExistedMappedStatement(Configuration configuration, String msId) {         MappedStatement mappedStatement = null;          try {             mappedStatement = configuration.getMappedStatement(msId, false);         } catch (Throwable var5) {             ;         }          return mappedStatement;     }      public Object plugin(Object target) {         return Plugin.wrap(target, this);     }      public void setProperties(Properties properties) {         this.msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties);         String dialectClass = properties.getProperty("dialect");         if (StringUtil.isEmpty(dialectClass)) {             dialectClass = this.default_dialect_class;         }          try {             Class<?> aClass = Class.forName(dialectClass);             this.dialect = (Dialect) aClass.newInstance();         } catch (Exception var6) {             throw new PageException(var6);         }          this.dialect.setProperties(properties);         String countSuffix = properties.getProperty("countSuffix");         if (StringUtil.isNotEmpty(countSuffix)) {             this.countSuffix = countSuffix;         }          try {             this.additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");             this.additionalParametersField.setAccessible(true);         } catch (NoSuchFieldException var5) {             throw new PageException(var5);         }     } }  
package com.anur.pagehelper.page;  /**  * Created by Anur IjuoKaruKas on 2018/6/8  */ public class PageSqlResolver {      public static final String SQL_SIGN = "AS limitable";      public static final String LIMIT_SIGN = "LIMIT ?";      public static final String LIMIT_SIGN_EX = "LIMIT ?, ?";      public static String resolveLimit(String pageSql) {         if (pageSql == null) {             return null;         }          if (pageSql.contains(SQL_SIGN)) {// 如果需要特殊分页             String changer = "";              if (pageSql.contains(LIMIT_SIGN_EX)) {                 changer = LIMIT_SIGN_EX;             } else if (pageSql.contains(LIMIT_SIGN)) {                 changer = LIMIT_SIGN;             }              pageSql = pageSql.replace(changer, "");             StringBuilder sqlBuilder = new StringBuilder(pageSql);              StringBuilder mae = new StringBuilder(sqlBuilder.substring(0, sqlBuilder.indexOf(SQL_SIGN)));// mae 截止sql语句到 limitable             StringBuilder uShiRo = new StringBuilder(sqlBuilder.substring(sqlBuilder.indexOf(SQL_SIGN), sqlBuilder.length()));// 剩余的              mae.insert(mae.lastIndexOf(")"), String.format(" %s", changer));              return mae.append(uShiRo)                       .toString();         } else {             return pageSql;         }     } } 

3、新增配置文件如下 注意,这里配置了我们的CustomPageInterceptor(2步骤里的那个类)作为插件,如果不进行此处配置,我们的修改是不起作用的。

/**  * Created by Anur IjuoKaruKas on 2017/12/13.  */ @Configuration public class MybatisConfiguration {      @Bean     public SqlSessionFactory sqlSessionFactoryBean(@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") DataSource dataSource) throws Exception {         SqlSessionFactoryBean factory = new SqlSessionFactoryBean();         factory.setDataSource(dataSource);         factory.setTypeAliasesPackage(Constant.MODEL_PACKAGE);          // 配置分页插件,详情请查阅官方文档         PageHelperProperties properties = new PageHelperProperties();         properties.setPageSizeZero("true");// 分页尺寸为0时查询所有纪录不再执行分页         properties.setReasonable("true");// 页码<=0 查询第一页,页码>=总页数查询最后一页         properties.setSupportMethodsArguments("true");// 支持通过 Mapper 接口参数来传递分页参数          CustomPageInterceptor pageInterceptor = new CustomPageInterceptor();         pageInterceptor.setProperties(properties.getProperties());         //  添加插件         factory.setPlugins(new Interceptor[]{pageInterceptor});          // 添加XML目录         ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();         factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));         return factory.getObject();     } }

4、sql语句注意事项 在需要被查询的主表上,你需要手动包装一层select,并将其别名设置为limitable。AS必须大写。

SELECT * FROM (SELECT *       FROM provider_order) AS limitable   LEFT JOIN order_info ON limitable.po_id = order_info.provider_order_id

这是原语句:

SELECT *       FROM provider_order limitable   LEFT JOIN order_info ON limitable.po_id = order_info.provider_order_id

5、查询时注意事项 在查询之前,我们需要将主表的主键(必须唯一)设置到countColumn中。

 Page page = PageHelper.startPage(0, 10);         page.setCountColumn("DISTINCT po_id");         List<ProviderOrder> providerOrderList = testService.getProviderOrderWithOrderInfoTest("%-%"); 

如果已经确保完成了上面的五个步骤,执行查询即可,我们将得到正确的连表查询结果。

支持连表等复杂查询的PageHelper——PageHelper5.1.4 Mybatis3.4.6 - VPS资讯

微信打赏

支持连表等复杂查询的PageHelper——PageHelper5.1.4 Mybatis3.4.6 - VPS资讯

支付宝打赏

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具