informix 数据库的分页

Posted

技术标签:

【中文标题】informix 数据库的分页【英文标题】:pagination for informix database 【发布时间】:2019-12-11 14:38:27 【问题描述】:

我正在尝试为 IBM Informix db 进行分页,但 Hibernate 方言有一些限制,因为它不会生成 LIMIT 查询。 当我检查 IBM Informix 手册时告诉我以下答案:-

"The Projection clause cannot include the SKIP, FIRST, or LIMIT keywords in these contexts:

when the SELECT statement is part of a view definition
in a subquery, except in the FROM clause of the outer query
in a cross-server distributed query in which a participating database server does not support the SKIP, FIRST, or LIMIT keywords."

我正在尝试为 LIMIT 类编写自己的实现,并在加载 Hibernate 方言时加载它。但是每次我启动我的应用程序时,它都会选择默认方言而不是我的。

hibernate 中存在一个问题 - https://hibernate.atlassian.net/browse/HHH-5414。

该补丁不适用于我的本地。 但我担心,由于 DB 本身不支持,那么如果我尝试手动执行此操作会有多高效,因为这将是基于偏移量的分页,我认为这会影响性能并且可能无法解决问题。

我想知道在考虑这些情况下可以做些什么来最好地支持informix 的分页。

【问题讨论】:

我最近看到了这篇文章:-discourse.hibernate.org/t/…。它谈到 - “使用提供 Informix10LimitHandler 的 Informix10Dialect。” 【参考方案1】:

是的,这个问题现在在 Hibernate 中得到了解决(至少在目前我们主要使用的 jboss EAP7 服务器附带的 5.3.10.Final-redhat-00001 中),你只需要添加你的

<property name="hibernate.dialect" value="org.hibernate.dialect.Informix10Dialect" />

到你的 persistence.xml 然后它工作正常。 works 我的意思是

行中的代码
if (pageSize > 0) 
    int firstResult = pageNo * pageSize - pageSize;
    query.setFirstResult(firstResult);
    query.setMaxResults(pageSize);

其中查询是 javax.persistence.Query。

诸如此类的触发查询的合理预期将是表单上的 SQL 'native' 输出

select skip <firstResult> limit <pageSize> [rest of the select statement]

发送到informix。然而,Hibernate 直到 Hibernate 5 才解决这个问题。

也许它不是很漂亮,但是如果您被困在古老的 JBOSS 或其他引入/需要古老休眠版本的可怕的旧平台中,您能做的就是简单地自己修复代码。不久前,我们曾经从

破解hibernate-core
hibernate-core-4.x.x.Final

被黑

hibernate-core-4.x.x.Final-pagination 

这只是替换类

org.hibernate.dialect.InformixDialect
org.hibernate.dialect.pagination.NoopLimitHandler
org.hibernate.dialect.pagination.FirstLimitHandler

让这些首先支持limitOffSet by

@Override
public boolean supportsLimitOffset() 
    return true;

然后我们只是以某种简单的方式实现了这些东西,例如

public final class InformixDialect extends Dialect 
..
private static final String SKIP = " SKIP ";
private static final String FIRST = " FIRST ";
private static final String SELECT = "select";
private static final int SELECT_LEN = SELECT.length();
..  
@Override        
public String getLimitString(String querySelect, int offset, int limit) 
    return new StringBuilder(querySelect.length() + 8)
            .append(querySelect)
            .insert(querySelect.toLowerCase().indexOf(SELECT) + SELECT_LEN, new StringBuilder(SKIP).append(offset).append(FIRST).append(limit).toString()).toString();

..

和(NoopLimitHandler完全一样)

public final class FirstLimitHandler extends AbstractLimitHandler 
..
private static final String SKIP = " SKIP ";
private static final String FIRST = " FIRST ";
private static final String EMPTY = "";
private static final String SELECT = "select";
private static final int SELECT_LEN = SELECT.length();
..
@Override
public int bindLimitParametersAtStartOfQuery(RowSelection selection, PreparedStatement statement, int index) 
    return 0;


@Override
public int bindLimitParametersAtEndOfQuery(RowSelection selection, PreparedStatement statement, int index) 
    return 0;

..
@Override
public String processSql(String sql, RowSelection selection) 
    if (selection == null || selection.getFirstRow() == null) 
        return sql;
    
    boolean hasOffset = LimitHelper.hasFirstRow(selection);
    int maxOrLimit = this.getMaxOrLimit(selection);
    String sqlOffset = hasOffset? SKIP + selection.getFirstRow(): EMPTY;
    String sqlLimit = maxOrLimit > 0 ? FIRST + this.getMaxOrLimit(selection): EMPTY;
    String sqlOffsetLimit = sqlOffset + sqlLimit;
    return new StringBuilder(sql.length() + 10).append(sql).insert(sql.toLowerCase(Locale.ROOT).indexOf(SELECT) + SELECT_LEN, sqlOffsetLimit).toString();

..

需要说,如果您可以使用 Hibernate 5,这当然是更好的选择

【讨论】:

以上是关于informix 数据库的分页的主要内容,如果未能解决你的问题,请参考以下文章

informix数据库分页

对数据分页后,2次查询的分页,点击上一页,下一页,首页,尾页,都会跳到2次查询之前的分页显示,怎么办

数据量太大,分页查询变慢,有啥优化查询的方法吗

java查询的分页思路!!

MongoDB分页处理方案(适用于一般数据库的分页方法)

jsp与mysql的分页