第 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()
连接多个Criteria
。
Lists
是来自 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
改为参数。
【讨论】:
不是说OR
ing这些部分的性能很差吗?
@geneb。他们做了吗?请提供一个来源,因为我希望 Oracle SQL“编译器”至少从版本 8 开始就可以考虑并优化X IN (...) OR X IN (...)
这种非常常见的用法。此外,这个问题的每个答案都使用OR
;我的只是 4 行而不是 20 行。这是我们多年来一直这样做的方式。以上是关于第 1000 条中的休眠标准分手的主要内容,如果未能解决你的问题,请参考以下文章
[Effective JavaScript 笔记]第51条:在类数组对象上复用通用的数组方法
求助,Windows 2008如何配置睡眠(Sleep)、休眠(hibernate)、混合休眠(Hybird Sleep)、标准睡眠(Standby)