我目前正在开发一个电子商务应用程序,我必须使用搜索功能显示可用产品列表。
与每次搜索一样,我必须在这里实施分页。
我使用mybatis作为我的ORM工具,使用mysql作为底层数据库。
在谷歌上搜索我找到了以下方法来完成这项任务:
客户端分页 :在这里,我将不得不从一个笔划中匹配搜索条件的数据库中获取所有结果,并在我的代码级别处理分页(可能是最终代码)。
服务器端分页:
使用mysql,我可以使用Limit和结果集的偏移量来构造一个类似的查询:
SELECT * FROM sampletable WHERE condition1>1 AND condition2>2 LIMIT 0,20
在这里,每次用户在搜索结果中导航时选择新页面时,我都必须传递偏移和限制计数。
任何人都可以说,
任何输入都是高度适应的。 谢谢。
答案 0 :(得分:7)
答案 1 :(得分:5)
如果您正在使用Mappers(比使用原始SqlSessions容易得多),应用限制的最简单方法是在映射函数的参数列表中添加RowBounds参数,例如:
// without limit
List<Foo> selectFooByExample(FooExample ex);
// with limit
List<Foo> selectFooByExample(FooExample ex, RowBounds rb);
在使用Mappers标题的the link Volodymyr posted中,这几乎是一个事后的想法,并且可以使用更多的重点:
您还可以将RowBounds实例传递给方法以限制查询结果。
请注意,对RowBounds的支持可能因数据库而异。 Mybatis文档暗示Mybatis将负责使用适当的查询。但是,至少对于Oracle来说,这可以通过对数据库进行非常低效的重复调用来处理。
答案 2 :(得分:3)
分页有两种类型,物理和逻辑
默认的mybatis分页是合乎逻辑的...因此当您选择一个大型数据库,例如100GB的blob时,rowbound方法仍然会非常慢
解决方案是使用物理分页
答案 3 :(得分:2)
如果您正在使用Spring MyBatis,则可以使用2个MyBatis查询以及有用的Spring Page
和Pageable
接口来手动实现分页。
您创建了更高级别的DAO
界面,例如UploadDao
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface UploadDao {
Page<Upload> search(UploadSearch uploadSearch, Pageable pageable);
}
...,其中Upload
映射到upload
表,而UploadSearch
是参数POJO,例如
@Data // lombok
public class UploadSearch {
private Long userId;
private Long projectId;
...
}
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);
}
}
DAO实现调用UploadMapper
的2个方法。这些是:
UploadMapper.searchUploads
-根据搜索参数(UploadSearch
)和Pageable
参数(包含偏移量/限制等)返回结果页面。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);
}
...以及包含动态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>
注意-
<sql>
块(以及<include refid=" ... " >
)在这里非常有用,可确保您的count
和select
查询对齐。此外,在排序时,我们使用条件,例如<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);
}
}
答案 4 :(得分:0)
如果您使用的是MyBatis Generator,您可能需要尝试官方网站上的Row Bounds插件:org.mybatis.generator.plugins.RowBoundsPlugin。这个插件将添加一个新版本
接受RowBounds参数的selectByExample
方法。