How to limit the results when using CriteriaQuery - java

I have inherited a groovy code base (that among other things) uses Hibernate as an ORM as part of Dropwizard and I've in the process of updating the dependencies I start seeing the following warnings.
org.hibernate.orm.deprecation: HHH90000022: Hibernate's legacy org.hibernate.Criteria API is deprecated; use the JPA javax.persistence.criteria.CriteriaQuery instead
As an experiment I tried updating one of the queries to use the new CriteriaQuery API. However pretty quickly I ran into an issue, the old code uses setMaxResults(). I assume under the hood this is using the LIMIT to limit the number of results.
How to I limit the results of a CriteriaQuery to 1?
A related question, how do I do pagination with CriteriaQuery?
I tried reading through the Hibernate 5.3 users guide, (especially chapter 16 the the new API) searing for "limits" and "max results" and such and all the talk I could find was in the "Legacy Hibernate Criteria Queries".
I'd be happy to provide some example code if it helps, but you could just use the example from the manual (Example 534. Selecting an attribute) and show how to enhance it by limiting the results.

Define setFirstResult() and setMaxResults() on the Query like this (offset=0 and limit=10):
sessionFactory.getCurrentSession().createQuery(criteriaQuery).setFirstResult(0).setMaxResults(10).getResultList());

To paginate you just have to set the first and max (assuming you're passing in a Pageable Object:
criteria.setFirstResult(pageable.gotOffset());
criteria.setMaxResults(pageable.getPageSize());
Also, to limit, just call:
Criteria queryCriteria = session.createCriteria(MonthlySubscriber.class);
queryCriteria.setFirstResult(0);
queryCriteria.setMaxResults(1);
monthlySubscriberList = queryCriteria .list();

Related

Retrieving limited columns using jpa specifications

I am using spring boot JPA specifications for executing complex queries. However, the table I am querying contains more than 20 columns and I need to pull just 3. I tried cq.multiselect(...) but it didn't work and returned me the entity with all the columns.
On investigation, I got to know that it's a bug with specifications that's not yet fixed. Another option was to use projections but specifications can't be combined with projections. An attempt to do so returns the complete entity.
I do not want to switch to Querydsl or #Query approach since it's an existing code and I am stuck with specifications. Any pointers on how to limit the number of columns will be much appreciated :)
Got to know Spring boot JPA Specifications doesn't provide any way to limit the number of columns. There is a bug related to this feature and it's pending for more than 3 years now. Not sure if it will be available soon
Use QueryDslPredicateExecutor.findAll(Predicate predicate, Pageable
pageable) and then get the actual results back using PageRequest.of(0,
limit).
Querydsl limit record example

Hibernate 6: What is SQM?

In the Hibernate 6.0 Roadmap (https://github.com/hibernate/hibernate-orm/wiki/Roadmap6.0) SQM is mentioned as upcoming.
What is SQM?
In this roadmap the following short words describe it:
SQM integration: Improved performance for SQL generation and execution (smaller SQL, position-based extraction of results rather than name(alias)-based); Unified approach for HQL, JPQL and Criteria queries.
This is all I've found about SQM. Could someone please explain it a little more in detail? What exactly is it, how will it look like when it comes to coding, which benefits will it have?
SQM stands for Semantic Query Model, and it is the new entity query parser that addresses both JPQL and Criteria API.
The new parser is much more flexible, and it provides better SQL translation of entity queries.
From a user perspective, SQM provides more features like Window Functions, CTE (Common Table Expressions), Lateral Joins, etc.
SQM provides better performance as well since Criteria API is parsed directly to SQL.

Hibernate JPA EntityManager.createQuery() performance

I have a query which has 2 'in' Clauses. First in clause takes around 125 values and second in clause of query takes around 21000 values. Its implemented using JPA CriteriaBuilder.
Query itself executes very fast and return results within seconds. Only problem is entityManager.createQuery(CriteriaQuery) takes around 12-13 minutes to return.
I search all over SO, all the threads are related to performance of Query.getResultList. None of them discuss about performance of entityManager.createQuery(CriteriaQuery). If you have seen such behavior earlier, please let me know, how to resolve it.
My JDK version is 1.7. Dependency version of javaee-api is 6.0. Application is deployed on JBOSS EAP 6.4. But that's not the concern as of now, as I am testing my code using junit using EntityManager connected to actual Oracle database. If you require more information, kindly let me know.
A hybrid approach is to dynamically create a query and then save it as a named query in the entity manager factory.
At that point it becomes just like any other named query that may have been declared statically in metadata. While this may seem like a good compromise, it turns out to be useful in only a few specific cases. The main advantage it offers is if there are queries that are not known until runtime, but then reissued repeatedly. Once the dynamic query becomes a named query it will only bear the cost of processing once.
It is implementation-specific whether that cost is paid when the query is registered as a named query, or deferred until the first time it is executed.
A dynamic query can be turned into a named query by using the
EntityManagerFactory addNamedQuery()
Keep us informed by the result and good luck
I observed that, having single query with 21 IN clauses (each with 1000 expressions) and all combined with OR clauses, made query run slower. I tried another approach of executing every IN Clause as a part of separate query. So these 21 individual queries performed better overall.
Another issue I observed was that Query with CriteriaBuilder was slow when result set is huge (something like 20K rows in result set). I solved this issue by adding query hint to my typed query:
TypedQuery.setHint("org.hibernate.fetchSize", 5000);
Hope it will help others.
Code in Hibernate is not expected to be used for binding lots of params:
for ( ImplicitParameterBinding implicitParameterBinding : parameterMetadata.implicitParameterBindings() ) {
implicitParameterBinding.bind( jpaqlQuery );
}
Unfortunately you need to find different approach if you want to do something similar.

OpenJPA dirty read hint

We've got the following DAO stack:
DB2 9.7 Express-C
OpenJPA 2.0.1
Spring 3.0.5
Bitronix 2.1.1
How do you specify OpenJPA to add WITH UR sql clause to the end of the query?
I'd browsed sites and manuals alike for days, it should be something like this:
Query q = em.createQuery("select m from Magazine m where ... ");
q.setHint("openjpa.FetchPlan.ReadLockMode","WRITE");
List r = q.getResultList();
but alas, I've been unable to find a working OpenJPA property that would be passed as setHint() argument and yield WITH UR as result, so I use SpringJDBC queries which I unfortunately can't use any longer.
Any ideas? Thank you very much
OpenJPA doesn't support using the WITH UR clause with JPQL. You could always use a native query for this functionality.
I'm having quite a similar problem now — it would seem that setting:
query.setHint("openjpa.FetchPlan.Isolation", "READ_UNCOMMITTED");
would do the trick. Unfortunately, the source code reveals that the constant withURClause from org.apache.openjpa.jdbc.sql.DB2Dictionary is never read.
Additionally OpenJPA never takes into account a fetch plan hint if the query is not FOR UPDATE. I have a select statement that gets blocked on exclusive locks and it could really work with uncommitted data — a no-go with OpenJPA.

Using Hibernate-Search for Complex Queries instead of Criteria API

In an app using Wicket+Spring+JPA/Hibernate stack, I have an Inbox/Search page which should have quite complex search capabilities, where records saved in a database are filtered using a myriad of filtering options. So far I've used JPA Criteria API to build the database query but it's getting quite messy. I was wondering if Hibernate-Search would be a good fit for this even though I don't really need any full-text search capabilities, I just feel (from what I read about it) that producing the query might be a bit easier?
Sorry, but Hibernate Search is based on Lucence. It is not just an other query language.
Lucene does not serach for entities in your database, it search for attibutes in the Lucene index.
Hibernate Search add the functionality to connect the Entities from your Database to the Lucene Index.
Hibernate Search and Lucene are create tool when you need advanced full text search. But if you don't need it, it is only a lot of unnesseary work (and problems).
So, as long as you do not use Lucene, Hibernate Search does not fit your needs.
The primary use case for Hibernate Search is fulltext search. However, it can also be used to index/search simple attributes/criteria. Whether the syntax for writing the queries is simpler than a criteria query is a matter of taste.
If you are not using the fulltext search capabilities you have to consider that you are adding an additional step in your application. The search query will be run against the Lucene index which will return entity ids (unless projection is used). The matching entities will then be fetched from the database.
On the other hand, once you use Hibernate Search it is easy to "improve" your search by adding some fulltext search capabilities to some of your criteria (if possible).
Whether or not you are using Search, I think the key is to write some sort of framework which programmatically builds your queries - Search or Criteria queries.

Categories

Resources