Hibernate/JDBC 为 Informix 数据库生成错误的 SQL

Posted

技术标签:

【中文标题】Hibernate/JDBC 为 Informix 数据库生成错误的 SQL【英文标题】:Hibernate/JDBC generates wrong SQL for Informix database 【发布时间】:2013-10-07 07:53:22 【问题描述】:

我正在尝试使用标准 JPA 方法在我们的 Spring 应用程序中实现分页。这是一个非常简化的示例:

TypedQuery<Department> depsQuery = em.createQuery("select d from Department d", Department.class);
depsQuery.setFirstResult(20);
depsQuery.setMaxResults(10);
depsQuery.getResultList();

此查询应在 Informix 中生成类似于 select skip 20 first 10 的内容。但是,它会生成:

select first 30 department0_.id as ... from DEPARTMENT department0_

我在 JBoss 的 standalone.xml 中有 &lt;driver-class&gt;com.informix.jdbc.IfxDriver&lt;/driver-class&gt;,在 persistence.xml 文件中有 &lt;property name="hibernate.dialect" value="org.hibernate.dialect.InformixDialect" /&gt;。如何让 Hibernate/JDBC 产生正确的查询?

【问题讨论】:

【参考方案1】:

“org.hibernate.dialect.InformixDialect”不支持限制。这是课堂上的一个 sn-p:

public boolean supportsLimitOffset() 
        return false;
    

    public String getLimitString(String querySelect, int offset, int limit) 
        if ( offset > 0 ) 
            throw new UnsupportedOperationException( "query result offset is not supported" );
        
        return new StringBuffer( querySelect.length() + 8 )
                .append( querySelect )
                .insert( querySelect.toLowerCase().indexOf( "select" ) + 6, " first " + limit )
                .toString();
    

您可以扩展此类以创建自定义方言。然后覆盖以上两个方法。

public boolean supportsLimitOffset() 
    return true;


public String getLimitString(String querySelect, int offset, int limit) 
    return new StringBuffer( querySelect.length() + 8 )
            .append( querySelect )
            .insert( querySelect.toLowerCase().indexOf( "select" ) + 6," skip " + offset + " first " + limit).toString();

【讨论】:

我最终使用了InformixDialect,但这就是解决方案,谢谢。【参考方案2】:

我遇到了同样的问题,上面的答案对我没有帮助。 仅覆盖 getLimitString 方法没有任何效果。 我也必须覆盖 LimitHandler 并打开一些布尔标志。

import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.engine.spi.RowSelection;

public class TestDialect extends org.hibernate.dialect.InformixDialect 

    private static final LimitHandler LIMIT_HANDLER = new AbstractLimitHandler() 
        @Override
        public String processSql(String sql, RowSelection selection) 
            return getMyLimitString(sql, selection.getFirstRow(), selection.getMaxRows());
        

        @Override
        public boolean supportsLimit() 
            return true;
        

        @Override
        public boolean bindLimitParametersFirst() 
            return true; // must do, otherwise there will be an exception cause of preparedStatments
        
    ;

    //
    ////
    //

    public TestDialect() 
        super();
    


    @Override
    public LimitHandler getLimitHandler() 
        return LIMIT_HANDLER;
    

    @Override
    public String getLimitString(String querySelect, int offset, int limit)        
        return getMyLimitString(querySelect, offset, limit);
    

    public static String getMyLimitString(String querySelect, int offset, int limit) 
        /* SQL Syntax:
         * SELECT FIRST <limit> ...
         * SELECT SKIP <offset> FIRST <limit> ...
         */


        System.out.println("TestDialect.getMyLimitString()");

        if (offset < 0 || limit < 0) 
            throw new IllegalArgumentException("Cannot perform limit query with negative limit and/or offset value(s)");
        

        StringBuffer limitQuery = new StringBuffer(querySelect.length() + 10);
        limitQuery.append(querySelect);
        int indexOfEndOfSelect = querySelect.toLowerCase().indexOf("select") + 6;

        if (offset == 0) 
            limitQuery.insert(indexOfEndOfSelect, " first ?"  );
         else 
            limitQuery.insert(indexOfEndOfSelect, " skip ?" +   " first ?"  );
        

        return limitQuery.toString();
    

    @Override
    public boolean supportsLimit() 
        return true;
    

【讨论】:

以上是关于Hibernate/JDBC 为 Informix 数据库生成错误的 SQL的主要内容,如果未能解决你的问题,请参考以下文章

hibernate的速度问题--hibernate.jdbc.fetch_size和 hibernate.jdbc.batch_size

hibernate.jdbc.fetch_size和hibernate.jdbc.batch_size有什么区别?

Hibernate、JDBC 驱动程序和 OSGi 问题

hibernate.jdbc.fetch_size 的默认大小是多少?

为啥我们的 Spring/Hibernate/JDBC/Websphere 系统中的连接过早关闭?

MyBatis+Hibernate+JDBC对比分析