第 1000 条中的休眠标准分手

Posted

技术标签:

【中文标题】第 1000 条中的休眠标准分手【英文标题】:Hibernate Criterion IN Clause 1000 break up 【发布时间】:2013-01-29 21:56:23 【问题描述】:

嗨,我有这个大型的 oracle hibernate web 应用程序,它似乎给出了这个错误

ORA-01795: maximum number of expressions in a list is 1000

我需要一个由某人测试的 java 代码作为休眠用户定义的组件,以便尽可能容易地添加到我的屏幕中的搜索 java 类中,有人可以拥有这样的测试组件吗?

【问题讨论】:

【参考方案1】:

我从link 尝试了下面的代码,它似乎工作得很好,我会粘贴代码以防将来链接被破坏。

保持简单保持微笑:)

    /**
    * An utility method to build the Criterion Query IN clause if the number of parameter
    * values passed has a size more than 1000. Oracle does not allow more than
    * 1000 parameter values in a IN clause. Doing so a @link SQLException is
    * thrown with error code, 'ORA-01795: maximum number of expressions in a list is 1000'.
    * @param propertyName
    * @param values
    * @return
    */
import java.util.List;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author 2796
 */
public class SplitHibernateIn 

    private static int PARAMETER_LIMIT = 999;

    public static org.hibernate.criterion.Criterion buildInCriterion(String propertyName, List values) 
        org.hibernate.criterion.Criterion criterion = null;

        int listSize = values.size();
        for (int i = 0; i < listSize; i += PARAMETER_LIMIT) 
            List subList;
            if (listSize > i + PARAMETER_LIMIT) 
                subList = values.subList(i, (i + PARAMETER_LIMIT));
             else 
                subList = values.subList(i, listSize);
            
            if (criterion != null) 
                criterion = Restrictions.or(criterion, Restrictions.in(propertyName, subList));
             else 
                criterion = Restrictions.in(propertyName, subList);
            
        
        return criterion;
    

【讨论】:

仅供参考;这段代码在hibernate 3和oracle 10g上测试过 如果有人(像我一样)认为 IN 子句对于没有参数(对于作为参数传递的空列表)不应该返回任何内容,则可以修改此方法返回一个始终为假的 Criterion。我通过在方法顶部添加以下代码来做到这一点: if ((values == null) || values.isEmpty()) return Restrictions.sqlRestriction("(1=0)"); 【参考方案2】:

同样的想法,但使用 javax Predicate。

private static int PARAMETER_LIMIT = 999;

private static Predicate createInStatement(CriteriaBuilder cb, Path fieldName, List values) 
    int listSize = values.size();
    Predicate predicate = null;
    for (int i = 0; i < listSize; i += PARAMETER_LIMIT) 
        List subList;
        if (listSize > i + PARAMETER_LIMIT) 
            subList = values.subList(i, (i + PARAMETER_LIMIT));
         else 
            subList = values.subList(i, listSize);
        
        if (predicate == null) 
            predicate = fieldName.in(subList);
         else 
            predicate = cb.or(predicate, fieldName.in(subList));
        
    
    return predicate;

及用法

public List<Bean> getBeanList(List<Long> pkList) 
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Bean> query = cb.createQuery(Bean.class);
    Root<Bean> root = query.from(Bean.class);

    // "Bean_" is a @StaticMetamodel(Bean.class)
    Predicate inStatement = createInStatement(cb, root.get(Bean_.pk), pkList);

    query.select(root).where(inStatement);
    return entityManager.createQuery(query).getResultList();

【讨论】:

这不适用于限制为 2100 个参数的 MS SQL!似乎 JDBC 驱动程序连接了 OR-ed IN 子句?!【参考方案3】:

虽然目前的答案很好,但我认为这个更容易实现和理解:

private <T> Disjunction restrictionPropertyIn(String property, ArrayList<T> list) 
    Disjunction criterion = Restrictions.disjunction();
    for (List<T> idSubset : Lists.partition(list, 1000)) 
        criterion.add(Restrictions.in(property, idSubset));
    
    return criterion;

Restrictions.disjunction() 相当于使用Restrictions.or() 连接多个CriteriaLists 是来自 Guava 的实用程序类; partition(list, limit)list 拆分为大小为 limit 的子列表。

返回的Criterion 可以在任何需要Criterion 的地方按原样使用,例如:

List<Long> fiveThousandIds = Arrays.asList(1, 2, 3, ..., 999, 1000, 1001, ..., 5000);
Criteria crit = session.createCriteria(Employee.class);
crit.add(restrictionPropertyIn("employeeId", fiveThousandIds));
crit.list();

如果您需要支持具有不同IN 子句限制的不同DB,您可以将硬编码的1000 改为参数。

【讨论】:

不是说ORing这些部分的性能很差吗? @geneb。他们做了吗?请提供一个来源,因为我希望 Oracle SQL“编译器”至少从版本 8 开始就可以考虑并优化X IN (...) OR X IN (...) 这种非常常见的用法。此外,这个问题的每个答案都使用OR;我的只是 4 行而不是 20 行。这是我们多年来一直这样做的方式。

以上是关于第 1000 条中的休眠标准分手的主要内容,如果未能解决你的问题,请参考以下文章

休眠标准组结果按日期从时间戳

[Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法

求助,Windows 2008如何配置睡眠(Sleep)、休眠(hibernate)、混合休眠(Hybird Sleep)、标准睡眠(Standby)

带有子查询的休眠标准

使用休眠标准,有没有办法逃避特殊字符?

具有自定义数据库功能的休眠标准