#java #hibernate #jpa
Вопрос:
Я использую CriteriaBuilder из JPA для создания предложения long IN . Затем я обнаружил, что Oracle не поддерживает> 1000 элементов в предложении IN, поэтому мне нужно разделить это предложение на несколько, например in (?, ?, ?...) or in (?, ?, ?)
.
Это сделано, но я думаю, что нам нужно оптимизировать больше, поскольку переменная длина списка параметров не может быть оптимизирована на стороне БД: из-за изменения длины оптимизатор Oracle будет считать, что каждый запрос — это отдельный запрос, поэтому план выполнения изменится. Но я думаю, что это в основном один или два запроса, поскольку это предложение IN возможно, но редко содержит> 1000 элементов. Итак, если я смогу привязать список к одной переменной, это будет 99% времени in (?)
и 1% in (?) or in (?)
, что очень хорошо для Oracle, чтобы увидеть сходство.
Я обнаружил, что в Hibernate есть setParameterList()
подобное, и я думаю, что это то, что мне нужно. И я знаю, что могу unwrap()
перевести JPA Query
в режим гибернации Query
, например:
query.unwrap(org.hibernate.Query.class).getQueryString()
поэтому я хочу сделать то же самое, чтобы использовать метод setParameterList()
. Но Hibernate жалуется на «не найден именованный параметр».
org.hibernate.QueryParameterException: could not locate named parameter [excluded_orgIds0]
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100)
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:106)
at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:470)
at org.hibernate.internal.AbstractQueryImpl.setParameterList(AbstractQueryImpl.java:839)
....
Что мне теперь делать?
РЕДАКТИРОВАТЬ: я обнаружил, что setParameterList()
это уже вызывается в классе реализации, и он может сопоставить мой именованный параметр с параметром Hibernate positional, но похоже, что Hibernate наконец преобразует список в строку, поэтому привязка массива невозможна.
org.hibernate.ejb.QueryImpl.class
:
public TypedQuery<X> setParameter(String name, Object value) {
try {
if ( value instanceof Collection ) {
query.setParameterList( name, (Collection) value );
}
else {
query.setParameter( name, value );
}
registerParameterBinding( getParameter( name ), value );
return this;
}
catch (QueryParameterException e) {
throw new IllegalArgumentException( e );
}
catch (HibernateException he) {
throw getEntityManager().convert( he );
}
}
Почему?
Одна из возможностей: весь SQL похож:
select ih from ItemHistory as ih where ( ih.code=:param0 ) and ( ih.companyId in (select c.id from Company as c where ( ( c.organizationId in (:param1) ) or ( c.organizationId like :param2 ) or ( c.organizationId like :param3 ) ) and ( ( ( c.organizationId not in (:param4) ) and ( c.organizationId not in (:param5) ) ) and ( c.organizationId not like :param6 ) )) ) order by ih.eventDate desc
Когда я устанавливаю code
или eventDate
или not like ...
, я не использую параметр, а просто вводю значения ( queryBuilder.eq(column, "333")
) . Я использую только queryBuilder.parameter(List.class, param1)
там, где есть предложение IN .
Имеет ли позиционный параметр приоритет, чтобы, если я хочу использовать параметры, мне нужно было использовать их во всех местах?
Комментарии:
1. Вы не можете привязать список к одной переменной. Это не поддерживается JDBC и базой данных
2. Это также считается ответом, хорошо. Так или иначе, список будет преобразован в несколько параметров в строке, а для DB это будут разные запросы, поэтому оптимизатор не может включиться, верно? Эти структурно идентичные запросы, но с разным количеством параметров в предложении IN, будут проблемой для Oracle (и других DBs), верно?
3. Точно! Могу я спросить, почему у вас такое большое количество параметров IN?
4. Я не совсем понимаю, почему, поскольку они не поступают из БД. Я могу попытаться выяснить, почему, может быть, в понедельник.
5. Возможно, они из службы авторизации пользователя, другого микросервиса. Если это правда, у меня нет доступа к этой базе данных.