如何用mybatis进行分页?

Sha*_*war 8 mysql pagination hibernate mybatis

我目前正在开发一个电子商务应用程序,我必须使用搜索功能显示可用产品列表.

与每次搜索一样,我必须在这里实现分页.

我使用mybatis作为我的ORM工具,使用mysql作为底层数据库.

谷歌搜索我找到了以下方法来完成这项任务:

  1. 客户端分页 :在这里,我将不得不一次性从匹配搜索条件的数据库中获取所有结果,并在我的代码级别处理分页(可能是最终代码).

  2. 服务器端分页:使用mysql,我可以使用Limit和结果集的偏移量来构造如下的查询: SELECT * FROM sampletable WHERE condition1>1 AND condition2>2 LIMIT 0,20

在这里,每次用户在搜索结果中导航时选择新页面时,我都必须传递偏移和限制计数.

谁能告诉,

  1. 这将是实现分页的更好方法吗?
  2. mybatis支持更好的实现分页的方法,而不仅仅依赖于上面的SQL查询(比如hibernate标准API).

任何输入都是高度适应的.谢谢 .

Vol*_*kyi 8

我自己在sql查询中使用LIMIT的第二个opion.

但是有一系列方法支持使用RowBounds类进行分页.这是很好的MyBatis文档中描述这里

注意使用正确的结果集类型.


Tyd*_*eus 7

如果您正在使用Mappers(比使用原始SqlSessions容易得多),应用限制的最简单方法是在映射函数的参数列表中添加RowBounds参数,例如:

// without limit
List<Foo> selectFooByExample(FooExample ex);

// with limit
List<Foo> selectFooByExample(FooExample ex, RowBounds rb);
Run Code Online (Sandbox Code Playgroud)

这几乎是在Volodymyr在Using Mappers标题下发布的链接中提到的,并且可以使用更多的重点:

您还可以将RowBounds实例传递给方法以限制查询结果.

请注意,对RowBounds的支持可能因数据库而异.Mybatis文档暗示Mybatis将负责使用适当的查询.但是,对于Oracle至少,这可以通过对数据库进行非常低效的重复调用来处理.


Jun*_*Liu 5

分页有两种类型,物理的和逻辑的

  • 首先检索所有数据然后在内存中对它们进行排序的逻辑方法
  • 物理意味着数据库级子集选择

默认的 mybatis 分页是合乎逻辑的...因此,当您选择一个大型数据库(例如 100GB 的 blob)时,行绑定方法仍然会非常慢

解决方案是使用物理分页

  • 你可以通过mybatis拦截器做自己的事情
  • 或使用其他人预先制作的插件


bob*_*sie 5

如果您使用 Spring MyBatis,您可以使用 2 个 MyBatis 查询以及有用的 SpringPagePageable接口手动实现分页。

您创建一个更高级别的DAO接口,例如UploadDao

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface UploadDao {

    Page<Upload> search(UploadSearch uploadSearch, Pageable pageable);

}
Run Code Online (Sandbox Code Playgroud)

...其中Upload映射到upload表并且UploadSearch是参数 POJO 例如

@Data  // lombok
public class UploadSearch {

    private Long userId;
    private Long projectId;
    ... 

}
Run Code Online (Sandbox Code Playgroud)

UploadDao(注入MyBatis映射器)的实现UploadMapper如下:

public class DefaultUploadDao implements UploadDao {

    @Autowired
    private UploadMapper uploadMapper;

    public Page<Upload> searchUploads(UploadSearch uploadSearch, Pageable pageable) {
        List<Upload> content = uploadMapper.searchUploads(uploadSearch, pageable);
        Long total = uploadMapper.countUploads(uploadSearch);
        return new PageImpl<>(content, pageable, total);
    }

}
Run Code Online (Sandbox Code Playgroud)

DAO 实现调用 2 个方法UploadMapper。这些都是:

  1. UploadMapper.searchUploads- 根据搜索参数 ( UploadSearch) 和Pageable参数(包含偏移量/限制等)返回结果页。
  2. UploadMapper.countUploads- 返回总数,再次基于搜索参数UploadSearch。注意 -Pageable此处不需要参数,因为我们只是确定搜索参数过滤到的总行数,而不关心页码/偏移量等。

注入的UploadMapper界面看起来像......

@Mapper
public interface UploadMapper {

    List<Upload> searchUploads(
        @Param("search") UploadSearch search,
        @Param("pageable") Pageable pageable);

    long countUploads(
        @Param("search") UploadSearch search);

}
Run Code Online (Sandbox Code Playgroud)

...并且包含动态 SQL 的映射器 XML 文件例如upload_mapper.xml包含...

<mapper namespace="com.yourproduct.UploadMapper">

    <select id="searchUploads" resultType="com.yourproduct.Upload">
        select u.*
          from upload u
         <include refid="queryAndCountWhereStatement"/>
         <if test="pageable.sort.sorted">
             <trim prefix="order by">
                 <foreach item="order" index="i" collection="pageable.sort" separator=", ">
                     <if test="order.property == 'id'">id ${order.direction}</if>
                     <if test="order.property == 'projectId'">project_id ${order.direction}</if>
                 </foreach>
             </trim>
         </if>
        <if test="pageable.paged">
            limit #{pageable.offset}, #{pageable.pageSize}  
        </if>
        <!-- NOTE: PostgreSQL has a slightly different syntax to MySQL i.e. 
             limit #{pageable.pageSize} offset #{pageable.offset} 
        -->
    </select>

    <select id="countUploads" resultType="long">
        select count(1)
         from upload u
        <include refid="queryAndCountWhereStatement"/>
    </select>

    <sql id="queryAndCountWhereStatement">
        <where>
            <if test="search != null">
                <if test="search.userId != null"> and u.user_id = #{search.userId}</if>
                <if test="search.productId != null"> and u.product_id = #{search.productId}</if>
                ...
            </if>
        </where>
    </sql>
</mapper>

Run Code Online (Sandbox Code Playgroud)

注意 -<sql>块(以及<include refid=" ... " >)在这里非常有用,可以确保您的查询countselect查询保持一致。另外,排序时我们使用条件,例如<if test="order.property == 'projectId'">project_id ${order.direction}</if>映射到列(并停止 SQL 注入)。是${order.direction}安全的,因为 SpringDirection类是一个enum.

然后可以UploadDao从 Spring 控制器等注入和使用:

@RestController("/upload")
public UploadController {

    @Autowired
    private UploadDao uploadDao;  // Likely you'll have a service instead (which injects DAO) - here for brevity

    @GetMapping
    public Page<Upload>search (@RequestBody UploadSearch search, Pageable pageable) {
        return uploadDao.search(search, pageable);
    }

}
Run Code Online (Sandbox Code Playgroud)