Sql MyBatis RowBounds不限制查询结果
我正在开发一个无状态API,需要支持分页 我使用Oracle数据库。 我使用Spring和MyBatis来访问数据库 从文档中,我了解到我可以使用RowBounds类来限制查询返回的行数 但是,似乎没有对查询进行特殊优化以支持分页 例如,如果我将RowBounds设置为偏移100,共有50条记录,我希望查询中添加以下内容:Sql MyBatis RowBounds不限制查询结果,sql,spring,oracle,mybatis,Sql,Spring,Oracle,Mybatis,我正在开发一个无状态API,需要支持分页 我使用Oracle数据库。 我使用Spring和MyBatis来访问数据库 从文档中,我了解到我可以使用RowBounds类来限制查询返回的行数 但是,似乎没有对查询进行特殊优化以支持分页 例如,如果我将RowBounds设置为偏移100,共有50条记录,我希望查询中添加以下内容: (original query with the where clause...) and ROWNUM < 150 and ROWNUM >= 100 但这里
(original query with the where clause...)
and ROWNUM < 150
and ROWNUM >= 100
但这里什么都没有,只是我手动定义的查询
这对性能来说太糟糕了,因为我可能有几千个结果
我做错了什么
谢谢。Mybatis将许多事情留给正在使用的SQL驱动程序,而围绕RowBounds的确切行为似乎就是其中之一
请参阅,特别是以下章节:
不同的驾驶员能够达到不同的效率水平
在这方面。为了获得最佳性能,请使用结果集类型
SCROLL\u-SENSITIVE或SCROLL\u-SENSITIVE换言之:not
只向前看
默认设置显然是未设置的,但是您可以尝试在选择标记中使用SCROLL_SENSITIVE作为ResultSetType属性,看看这是否有帮助。请参阅以了解更多信息
如果这不起作用,您可以通过放弃RowBounds的使用来解决这个问题,并实现一个SettingsBean类或类似的类,您的select标记将其作为参数类型,其中包含偏移量和限制字段,或者rowStart和rowEnd对Oracle更有意义,然后,您可以根据需要在运行时设置它们,并在执行select时将它们动态插入SQL
在编写更多代码的同时,您可以通过纯动态SQL完全按照自己的意愿控制行为。我对Mybatis和Postgres采用了类似的方法,效果很好
因此,您将使用这些字段及其getter和setter实现SettingsBean类,然后您的select语句可能会如下所示:
<select
id="selectFoo"
parameterType="com.foo.bar.SettingsBean">
select *
from foo
where rownum >= #{rowStart}
and rownum < #{rowEnd}
</select>
我找到了解决这个问题的简单方法。我遵循了@khampson推荐的Mybatis指令,并将一个RowBounds实例传递给映射程序,没有强制执行任何限制
RowBounds rowbounds = new RowBounds(0, resultLimit);
roster = tableMapper.selectAll(rowbounds);
映射器java
public List<Row> selectAll(RowBounds rowbounds);
映射器xml
<select id="com.TableMapper.selectAll" resultMap="row" timeout="10">
SELECT * FROM table;
</select>
只需将LIMIT{param1.offset}、{param1.LIMIT}添加到映射器的xml中,就可以产生我想要的行为
<select id="com.TableMapper.selectAll" resultMap="row" timeout="10">
SELECT * FROM table LIMIT #{param1.offset}, #{param1.limit};
</select>
我测试了Postgres数据库和AngularUI的分页。第一页是N°1,如果调用第N°0页,服务将返回所有数据
java服务:
java映射器:
xml映射器:
Rownum在Oracle中是一个伪列,这意味着它将在最后阶段添加到结果集。这意味着,将rownum与大于1的任何值进行比较总是不会返回任何记录。有两个选项可以修改SQL语句:
将rownum包装为嵌套查询:
谢谢RowBounds似乎永远不会使用Oracle rownum技术。此外,resultSetType设置似乎仅与有状态、基于web的应用程序相关,例如显示分页结果的网页。我将无状态EJB与Spring和MyBatis一起使用,所以我想在我的情况下,它会有什么不同?看来我得重新使用rownum解决方案了。我真的认为MyBatis团队应该更清楚地传达RowBounds的局限性。他们把它描述为一种简单抽象的分页方式,但实际上它的用途非常有限。当然,没问题。从理论上讲,即使在无状态应用程序中,它也可以工作——只需要具有不同偏移量和限制的顺序查询。然而,这实际上取决于Oracle驱动程序如何处理它,因为一次获取的行数取决于JDBC层,而JDBC层又依赖于Oracle、Postgres等各个驱动程序。。我同意这是为了让事情变得更简单。我发现Mybatis在处理更复杂类型(如字符串数组)的映射器时也是如此。
public List<Foo> selectAll(int currentPage, int itemsPerPage);
int offset = (currentPage - 1) * itemsPerPage;
RowBounds rowbounds;
if(currentPage == 0){
rowBounds = new RowBounds();
} else {
rowBounds = new RowBounds(currentPage, itemsPerPage);
}
return fooMapper.selectAll(rowBounds);
}
public List<Foo> selectAll(RowBounds rowbounds);
<select id="selectAll" resultMap="Foo">
SELECT * FROM foo;
</select>
select *
from (
select a.*, ROWNUM rnum
from .... a
where ...
and ROWNUM <= :max_rows
order by -- important
)
where rnum >= :offset
select *
from (
select a.*, ROW_NUMBER() OVER (ORDER BY id) rnum
from ....
-- order by is not important here
)
where rnum between 30 and 50;