Dynamic JPA count query not responding - java

I have created in a Spring Boot project a dynamic function that builds dynamic JPA queries with pagination. The main and count query are built correctly at runtime, I have even tested them directly in DB and they work fine. The problem is when the count statement is executing, the query never respond and does not show error messages. The count query built at runtime takes 4565ms in SQLDeveloper tool.
I share a code snippet and an image of where the logs are stopped...
Page<T> resultPage;
....
//create main JPA query
Query mainQuery = coreEntityManager.createQuery(queryBuilder.toString(), resultClass);
//create count JPA query
Query countQuery = coreEntityManager.createQuery(countQueryBuilder);
//set pageable params
int pageNumber = pageable.getPageNumber();
int pageSize = pageable.getPageSize();
//set first result cursor in main query
mainQuery.setFirstResult((pageNumber) * pageSize);
//set max result values in main query
mainQuery.setMaxResults(pageSize);
//set parameters in queries
for (String key : parameterMap.keySet()) {
//main query
mainQuery.setParameter(key, parameterMap.get(key));
//count query
countQuery.setParameter(key, parameterMap.get(key));
}
//run main query
List<T> fooList = mainQuery.getResultList();
//check result
if (fooList == null || fooList.size() == 0) {
//if empty return
resultPage = new CustomPage<T>(new ArrayList<T>());
} else {
//if contains values return pageable values
Long size= (Long) countQuery.getSingleResult();
log.debug("Size result query: {}",size);
resultPage = new CustomPage<T>(fooList, pageable, size);
}
return resultPage;

Related

Spring Boot - NamedParameterJdbcTemplate giving incorrect count of rows affected

In my DAO repository class below is the implementation
//Return the number of rows affected
public int deleteFeed(long feedId) {
String sqlQuery = "UPDATE feed SET trash = TRUE WHERE id = :id";
MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("id", feedId);
return namedParameterJdbcTemplate.update(sqlQuery, paramSource);
}
For the same feedId passed every time, the count result comes as 1 for the number of rows affected. If I run the same query in MySQL workbench, I am getting 0 rows affected.
Note: I am pointing to same DB in app and workbench.

How to get total result count from entity manager query

I am working on pagination using spring boot. I am trying get total count of results from entity manager query for the pagination. For that I am getting maxresults to show from query, but how can i get total count of results.Please tell me i am new to enity manager.
#Override
public List<User> getsearchresults(String result) {
String query = "FROM User WHERE (education = :education) OR (city = :city)";
return em
.createQuery(query,User.class)
.setParameter("education",education)
.setParameter("city",city)
.setMaxResults(5)
.getResultList();
}
this is how i write query which returns results but i need total number of result count.How can i do that plesase help me.

Sliced result using mongo template for the document(not nested)

How to retrieve Page result using mongo template
I have a scenario like below :
final Pageable pageableRequest = PageRequest.of(offset, limit);
Criteria criteria = where("");
if (null != type) {
criteria = criteria.and("type").is(type);
}
if (null != revision) {
criteria = criteria.and("current_revision_data.data.revision_start").is(revision);
}
Query query = query(criteria).with(pageableRequest);
Page<Invoice> invoices = mongoTemplate.find(query, Invoice.class);
Could someone point me how to get page of the result?
EDIT : To be more specific the last line that is :
Page invoices = mongoTemplate.find(query, Invoice.class);
is a compilation failure.
I would like to get Paged results which I could not find using MongoTemplate
Thanks

Hibernate is 1000 times slower than sql query

I have this setup
#Table(name ="A")
EntityA {
Long ID;
List<EntityB> children;
}
#Table(name ="B")
EntityB {
Long ID;
EntityA parent;
EntityC grandchild;
}
#Table(name ="C")
EntityC {
Long ID;
}
The SQL query is this (I omitted irrelevant details):
select top 300 from A where ... and ID in (select parent from B where ... and grandchild in (select ID from C where ...)) order by ...
The sql query in direct database or through Hibernate (3.5) SQL runs 1000 faster than using Criteria or HQL to express this.
The SQL generated is identical from HQL and Criteria and the SQL I posted there.
[EDIT]: Correction - the sql was not identical. I didn't try the Hibernate style parameter setting on the management studio side because I did not realize this until later - see my answer.
If I separate out the subqueries into separate queries, then it is fast again.
I tried
removing all mappings of child, parent, ect.. and just use Long Id references - same thing, so its not a fetching, lazy,eager related.
using joins instead of subqueries, and got the same slow behaviour with all combinations of fetching and loading.
setting a projection on ID instead of retrieving entities, so there is no object conversion - still slow
I looked at Hibernate code and it is doing something astounding. It has a loop through all 300 results that end up hitting the database.
private List doQuery(
final SessionImplementor session,
final QueryParameters queryParameters,
final boolean returnProxies) throws SQLException, HibernateException {
final RowSelection selection = queryParameters.getRowSelection();
final int maxRows = hasMaxRows( selection ) ?
selection.getMaxRows().intValue() :
Integer.MAX_VALUE;
final int entitySpan = getEntityPersisters().length;
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
final PreparedStatement st = prepareQueryStatement( queryParameters, false, session );
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
// would be great to move all this below here into another method that could also be used
// from the new scrolling stuff.
//
// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
// that I could do the control breaking at the means to know when to stop
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final List results = new ArrayList();
try {
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
if ( log.isTraceEnabled() ) log.trace( "processing result set" );
int count;
for ( count = 0; count < maxRows && rs.next(); count++ ) {
if ( log.isTraceEnabled() ) log.debug("result set row: " + count);
Object result = getRowFromResultSet(
rs,
session,
queryParameters,
lockModesArray,
optionalObjectKey,
hydratedObjects,
keys,
returnProxies
);
results.add( result );
if ( createSubselects ) {
subselectResultKeys.add(keys);
keys = new EntityKey[entitySpan]; //can't reuse in this case
}
}
if ( log.isTraceEnabled() ) {
log.trace( "done processing result set (" + count + " rows)" );
}
}
finally {
session.getBatcher().closeQueryStatement( st, rs );
}
initializeEntitiesAndCollections( hydratedObjects, rs, session, queryParameters.isReadOnly( session ) );
if ( createSubselects ) createSubselects( subselectResultKeys, queryParameters, session );
return results; //getResultList(results);
}
In this code
final ResultSet rs = getResultSet( st, queryParameters.hasAutoDiscoverScalarTypes(), queryParameters.isCallable(), selection, session );
it hits the database with the full SQL, but there are no results collected anywhere.
Then it proceeds to go through this loop
for ( count = 0; count < maxRows && rs.next(); count++ ) {
Where for every one of the expected 300 results, it ends up hitting the database to get the actual result.
This seems insane, since it should already have all the results after 1 query. Hibernate logs do not show any additional SQL being issued during all that time.
Anyone have any insight? The only option I have is to go to native SQL query through Hibernate.
I finally managed to get to the bottom of this. The problem was being caused by Hibernate setting the parameters separately from the actual SQL query that involved subqueries. So native SQL or not, the performance will be slow if this is done. For example this will be slow:
String sql = some sql that has named parameter = :value
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.setParameter ("value", someValue);
List<Object[]> list = (List<Object[]>)sqlQuery.list();
And this will be fast
String sql = some native sql where parameter = 'actualValue'
SQLQuery sqlQuery = session.createSQLQuery(sql);
List<Object[]> list = (List<Object[]>)sqlQuery.list();
It seems that for some reason with letting Hibernate take care of the parameters it ends up getting stuck in the resultSet fetching. This is probably because the underlying query on the database is taking much longer being parameterized. I ended up writing the equivalent of Hibernate Criteria and Restrictions code that sets the parameters directly as above.
We noticed a similar behaviour in our system.
And also encountered that writing the query with hardcoded parameters instead of using setParameter() would fixed the issue.
We are using MS SQL Server and after further investigation we noticed the the root cause of our issue is a default configuration of the sql server driver that transmits the query parameters as unicode. This lead to our indices being ignored since they were based on the ascii values on the queried columns.
The solution was to setup this property in the jdbc url : sendStringParametersAsUnicode=false
More details can be found here.
https://stackoverflow.com/a/32867579

hibernate java select queries

i am new to this and today i tried to play hibernate with a method that returns the result of selected row...if is selected then it can return the result in int.. here is my method
public int validateSub(String slave, String source, String table){
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Query q = session.createQuery("from Subscribers where slave = :slave AND source = :source AND tbl = :tbl");
q.setParameter("slave", slave);
q.setParameter("source", source);
q.setParameter("tbl", table);
int result = q.executeUpdate();
return result;
}
from this method i tried to validate the 3 values that i get from the Subscribers table but at the end i tried to compile having this error
Exception in thread "Thread-0" org.hibernate.hql.QueryExecutionRequestException: Not supported for select queries [from com.datadistributor.main.Subscribers where slave = :slave AND source = :source AND tbl = :tbl]
You can have a look at the below links that how executeUpdate works, one is from the hibernate docs and other the java docs for JPA which defines when the exception is thrown by the method
http://docs.oracle.com/javaee/6/api/javax/persistence/Query.html#executeUpdate()
https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/Query.html#executeUpdate()
Alternatively you can use
List list = query.list();
int count = list != null ? list.size() : 0;
return count;
you are running a select query, Eventhough you are not using the select keyword here hibernate will add that as part of the generated SQL.
what you need to do to avoid the exception is the say
q.list();
now, this will return a List (here is the documentation).
if you are trying to get the size of the elements you can say
Query q = session.createQuery("select count(s) from Subscribers s where slave = :slave AND source = :source AND tbl = :tbl");
Long countOfRecords = (Long)q.list().get(0);
you can execute update statements as well in HQL, it follows a similar structure as SQL (except with object and properties).
Hope this helps.
here you want to select record so it is posible without select key word
sessionFactory sesionfatory;
ArrayList list = (ArrayList)sessionfactory.getCurruntSession().find(from table where name LIKE "xyz");
long size = list.get(0);
I also happened to make the same mistake today.
Your SQL statement is not correct.
You can try:
DELETE from Subscribers WHERE slave = :slave AND source
Try this:
int result = q.list().size();

Categories