reduce prepared statement count in hibernate - java

i am struggling with hibernate prepared statement count.
I am using the following JPA criteria query:
int count = 30
EntityManager manager = ...
CriteriaBuilder builder = manager.getCriteriaBuilder();
CriteriaQuery<String> select = builder.createQuery(String.class);
Root<AdministrationParameter> root = select.from(AdministrationParameter.class);
select.select(root.get(AdministrationParameter_.value));
ParameterExpression<String> peF1 = builder.parameter(AdministrationParameter_.context.getBindableJavaType(), "f1");
ParameterExpression<String> peF2 = builder.parameter(AdministrationParameter_.parameter.getBindableJavaType(), "f2");
Predicate p1 = builder.equal(root.get(AdministrationParameter_.context), peF1);
Predicate p2 = builder.equal(root.get(AdministrationParameter_.parameter), peF2);
select.where(p1, p2);
List<String> results = Collections.emptyList();
TypedQuery<String> query = manager.createQuery(select);
for (int i = 0; i < count; i++) {
query.setParameter(peF1, administrationParameterTypeInterface.getContext());
query.setParameter(peF2, administrationParameterTypeInterface.getParameter());
query.getResultList();
}
The count variable is to execute the query n times, e.g. to run a db trace in background (the query is executed against a db2 database).
Assume count = 30
The db2 trace says, there are "30 prepares" and "30 describes", the "statement found count = 30".
Hibernate give me the same values:
EntityManagerFactory factory = ...;
SessionFactory sessionFactory = factory.unwrap(SessionFactory.class);
statistics = sessionFactory.getStatistics();
Statistics statistics = statistics.setStatisticsEnabled(true);
...running the query above...
System.out.println("prepared statement count: " + statistics.getPrepareStatementCount());//is 30
System.out.println("query cache hit count: " + statistics.getQueryCacheHitCount());//0
System.out.println("query cache miss count: " + statistics.getQueryCacheMissCount());//0
System.out.println("query execution count: " + statistics.getQueryExecutionCount());//30
According to the javadoc https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/stat/Statistics.html the statistics.getPrepareStatementCount() is "The number of prepared statements that were acquired".
Shouldn't it be 1?

Which Hibernate version are you using? This might be a bug that has already been fixed in newer versions. If updating doesn't help please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.

Related

Pessimistic Lock with Update Query

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Query updateQuery = session.createQuery("UPDATE Lot l SET l.currentRate = l.currentRate + 100, l.lastOwner = :lastowner WHERE l.id = :lotid", null);
updateQuery.setLockMode(LockModeType.PESSIMISTIC_WRITE);
So, here is my code fragment. I got an exception: java.lang.IllegalStateException: Expecting a SELECT query : UPDATE Lot l SET l.currentRate = l.currentRate + 100, l.lastOwner = :lastowner WHERE l.id = :lotid when I try to call setLockMode.
Why? Am I doing something wrong?
See the Java doc of the method you are trying to call: https://docs.oracle.com/javaee/6/api/javax/persistence/Query.html#setLockMode(javax.persistence.LockModeType)
It explicitly says, that an IllegalStateException will be thrown if you execute this on a non-SELECT statement.

JPA EntityManager updates object before transaction has finished? [duplicate]

I have native query to run :
String sqlSelect =
"select r.id_roster as id, " +
"count(roster_cat.id_category), " +
" sum(case when roster_cat.id_category IN ( :categoryIds) then 1 else 0 end) as counter " +
"from roster r " +
"inner join roster_sa_categories roster_cat " +
"on r.id_roster = roster_cat.id_roster " +
"where r.day = :dayToLookFor " +
"and r.id_shop = :idShop " +
"group by r.id_roster " +
"having count(roster_cat.id_category) = :nrCategories " +
"and count(roster_cat.id_category) = counter" ;
Query selectRostersQuery = entityManager.createNativeQuery(sqlSelect);
selectRostersQuery.setParameter("categoryIds", Arrays.asList(categoryIds));
selectRostersQuery.setParameter("dayToLookFor", day.toString());
selectRostersQuery.setParameter("idShop", shopId);
selectRostersQuery.setParameter("nrCategories", categoryIds.length);
List<Integer> rosterIds = new ArrayList<>();
List<Object> result = (List<Object>) selectRostersQuery.getResultList();
For some reason Hibernate choses to do an update before executing the select and it is really interfering with my data
Hibernate: /* update domain.Roster */ update roster set day=?, employee_count=?, interval_end=?, interval_start=?, id_shop=? where id_roster=?
Hibernate: /* update Roster */ update roster set day=?, employee_count=?, interval_end=?, interval_start=?, id_shop=? where id_roster=?
Hibernate: /* dynamic native SQL query */ select r.id_roster as id, count(roster_cat.id_category),sum(case when roster_cat.id_category IN ( ?) then 1 else 0 end) as counter from roster r inner join roster_sa_categories
roster_cat on r.id_roster = roster_cat.id_roster where r.day = ? and r.id_shop = ? group by r.id_roster having count(roster_cat.id_category) = ? and count(roster_cat.id_category) = counter
Any help would be appreciated,Thank you
What you describe is precisely what Hibernate's FlushMode.AUTO implies.
Any modifications in the Persistence Context (1LC) at the time a query is executed will be automatically flushed prior to executing the query, guaranteeing that the results returned by the database match that which was cached by in-memory modifications.
If the query is going to return entities that you're seeing the update for, then you should likely re-evaluate your operations, making sure that the query fires prior to the update to avoid the flush operation, which can be quite expensive depending on the volume of entities in your Persistence Context.
If you are absolutely sure that the changes you're seeing flushed won't be returned by the query in question, you can always force the query not to cause a flush by setting the flush mode manually:
Query query = session.createQuery( ... );
query.setFlushMode( FlushMode.COMMIT );
List results = query.list();
But only do this if you're sure that the query wouldn't then be reading uncommitted changes as this can cause lots of problems and lead to long debug sessions to understand why changes are being inadvertantly lost by your application.

Unexpected behaviour of SELECT query after UPDATE

Following is the logic in my java code :
con.setAutoCommit(false);
int starIndex = 0;
List Details = new ArrayList();
while (true) {
isRsEmpty = true;
String my_Query = "select * from x,y,z where"
+ " x.a = y.b"
+ " x.a = z.c"
+ "y.b = z.e"
+ " ORDER BY a ASC"
+ " limit 5"
+ " offset " + starIndex;
preparedStatement = con.prepareStatement(my_Query);
rs = preparedStatement.executeQuery();
while (rs.next()) {
isRsEmpty = false;
//Other processing steps
starIndex++;
Details.add(rs.getInt("id"));
}
if(isRsEmpty){
starIndex = 0;
}
Iterator itr = Details.iterator();
String updateTable = "UPDATE x SET status = ? where i = ? and j = ? and k = ?";
updatePreparedStatement = con.prepareStatement(updateTable);
while (itr.hasNext()) {
updatePreparedStatement.setInt(1, 1);
updatePreparedStatement.setString(2, "zzz");
updatePreparedStatement.setInt(3, 9);
updatePreparedStatement.setInt(4, 10);
updatePreparedStatement.addBatch();
}
updatePreparedStatement.executeBatch();
con.commit();
Details.clear();
}
The Problem :
I have 13 entries in my table which meets the select query.
When I first time run the query my Limit is 5 and Offset is 0 and I get
5 records correctly from the table and the selected 5 records are updated.
After doing the update to the table when the select query runs again it gives me 3 records.This is unexpected since I have more 8 records left in the table.Again the 3 records are updated.
Again when the select query runs it gives me 0 records.
Then again a select query runs which gives me 5 records and updates the 5 records.
I am not able to understand this behaviour. If I run my select query without update then it runs correctly which gives me 5,5,3 records , but with the above logic it gives me 5,3,0,5 records.
What is the problem here ?
Note : In the above program all the variables like PreparedStatement and other are declared correctly.
Thank you
Is there any chance you are missing "and" keyword between your conditions in the select query?
String my_Query = "select * from x,y,z where"
+ " x.a = y.b"
+ " AND x.a = z.c"
+ " AND y.b = z.e"
+ " ORDER BY a ASC"
+ " limit 5"
+ " offset " + starIndex;
I don't know if that would solve the problem but I find it weird that it works like this.

Native query not running in HsqlDb using Spring-Junit4

I have a method in my DAO which is querying a Oracle database and it is working fine in the application. However for testing we are using an Hsqldb and using Spring-junit for the tests. The same method returns an error during the tests because as far I have seen HSQL does not support subqueries so I'm getting:
Caused by: org.hsqldb.HsqlException: unexpected token: START required: )
Could you help me about how to proceed in this case? Could be possible to mock this method using Spring to not really do the call but give me some predefined result by configuration?
Any advice will be very welcome!
Here is the method:
private Long getRootParent(Long id) {
StringBuilder sqlQuery = new StringBuilder();
sqlQuery.append("SELECT ID FROM ");
sqlQuery.append(" ( SELECT MAX(level) , ff.ID FROM FOREF_FUND ff ");
sqlQuery.append(" START WITH ff.ID = ? ");
sqlQuery.append(" CONNECT BY PRIOR ff.PARENT_FK = ff.ID ");
sqlQuery.append(" GROUP BY ff.ID ORDER BY MAX (level) DESC ) ");
sqlQuery.append(" where rownum = 1 ");
SQLQuery query = this.createSQLQuery(sqlQuery.toString());
query.setParameter(0, id);
List result = query.list();
if (result != null && !result.isEmpty()) {
return ((BigDecimal) result.get(0)).longValue();
}
return null;
}

set max results in hibernate not working as per requirement

This is my query which is written using HQL. My requirement is as follows.
I've 45 records and I want to fetch 10 records each time. It gives successfully up to 40 records. But from 41-45 records, the query returns empty list.
query1 = session
.createQuery(
"FROM mongo c where "
+ "c.ad='555rs5' and "
+ "c.cId='44444sf' and "
+ "c.langId='59ecc8' and c.date < '"
+ tempDate + "' ORDER BY -date")
.setMaxResults(10);
Anything wrong in my query? Please let me know.
Regards
Naresh Veluri
For Hibernate pagination, next to the setMaxResults() method, you also need the setFirstResult() method. Check out this page.
I guess there must be a problem in your loop.
As per the K.C. answer you have not set setFirstResult() I dont know how your query fetching next records.Read Hibernate Doc - setFirstResult().
Query setFirstResult(int firstResult)
Set the first row to retrieve. If not set, rows will be retrieved beginnning from row 0.
Parameters:
firstResult - a row number, numbered from 0
Try below code hope this will help you to solve your problem.
boolean flag = true;
int firstResult = 0;
int pageSize = 10;
int maxResult = 10;
while(flag) {
query1 = session.createQuery("FROM mongo c where "
+ "c.ad='555rs5' and "
+ "c.cId='44444sf' and "
+ "c.langId='59ecc8' and c.date < '"
+ tempDate + "' ORDER BY -date");
query1.setFirstResult(firstResult);
query1.setMaxResults(maxResult);
List<mongo> = query1.list();
//terminate loop if list is empty or records less than pagesize.
if(list.isEmpty() || list.size() < (maxResult-firstResult)) {
flag = false;
} else {
firstResult = firstResult + pageSize;
maxResult = maxResult + pageSize;
}
}

Categories

Resources