Using Hibernate setFirstResult without any ordering - java

I am new to hibernate. I am confused with criteria's setFirstResult method.
From the documentation it seems hibernate returns rows from the the given number.
Since SQL query does not guarantee the ordering of rows without order by clause,
how setFirstQuery works in this case(without orderBy clause)?
Does hibernate read index information from the database?
If I execute same SQL query multiple times, ordering might change, in this case how setFirstResult work?

Hibernate can not do something by its own unless its supported by underlying databases. Because Hibernate queries finally get transformed to Sql only.
Having said that it uses underlying databases capabilities like for PostgresSQL and MySQL it will generate query like limit ? offset ? .
You can add custom order using addOrder
.addOrder( Order.asc("name") )

It is your task to add an order by, the function as you noticed won't guarantee same results if executed several times over the same set of data.
setFirstResult is typically used in pagination.

Related

Oracle: Result set in insertion order

In the Oracle database, the select statement, select * from tablename, does not give output in the order of insertion. In few articles, we have found that the Oracle database stores the row information based on Rowid.
We are using Oracle in a web application based on Java and there is a requirement to display the data in order of insertion in each module. So, applying an order by clause on each table is not feasible and can degrade the application's performance.
Is there any other way that the select statement returns data in insertion order?
Oracle version used is "Oracle Database 19c Standard Edition 2 Release 19.0.0.0.0 - Production Version 19.3.0.0.0"
Oracle is a relational database. In it, rows don't have any particular order which means that select statement might return result in different order when you run it several times. Usually it doesn't, but - if there are a lot of inserts/deletes - sooner or later you'll notice such a behavior. Therefore, the only certain way to return rows in desired order is to use - ta-daaa! - order by clause.
Also, you'll have to maintain your own order of insertion. A simple way to do that is to use a column whose source is a sequence.
I would check here first: previous-post
I would recommend not relying on any ordering unless you specify order by.
But what is the deficiency of adding something like ORDER BY ROWNUM ASC; to your queries? You can trim your result sets ( paginate ) or even only do it to the entities you want to 'maintain insertion order'.
Are you using anything for entity management? Hibernate has some defaults you could use as well. - Post some code examples and can provide additional help.

Is there a way to make query return a ResultSet?

I have the following query:
#Select("SELECT* FROM "+MyData.TABLE_NAME+" where data_date = #{refDate}")
public List<MyData> getMyData(#Param("refDate") Date refDate);
This table data is HUGE! Loading so many rows in memory is not the best way!
Is it possible to have this same query return a resultset so that I can just iterate over one item?
edit:
I tried adding:
#ResultType(java.sql.ResultSet.class)
public ResultSet getMyData(#Param("refDate") Date refDate);
but it gives me:
nested exception is org.apache.ibatis.reflection.ReflectionException: Error instantiating interface java.sql.ResultSet with invalid types () or values (). Cause: java.lang.NoSuchMethodException: java.sql.ResultSet.<init>()
I'd suggest you use limit in your query. limit X, Y syntax is good for you. Try it.
If the table is huge, the query will become slower and slower. Then the best way to to iterate will be to filter based on id and use limit.
such as
select * from table where id>0 limit 100 and then
select * from table where id>100 limit 100 etc
There are multiple options you have ...
Use pagination on database side
I will just suppose the database is oracle. However other db vendors would also work. In oracle you have a rownum with which you can limit number of records to return. To return desired number of records you need to prepare a where clause using this rownum. Now, the question is how to supply a dynamic rownum in a query. This is where dynamic sqls of mybatis comes in use. You can pass these rownum values inside a parameter map which there onwards you can use in your query inside a mapper xml using a #{} syntax. With this approach you filter the records on db level itself and only bring or prepare java objects which are needed or in the current page.
Use pagination on mybatis side
Mybatis select method on sqlSession has a Rowbounds attribute. Populate this as per your needs and it will bring you those number of records only. Here, you are limiting number of records on mybatis side whereas in first approach the same was performed on db side which is better performant .
Use a Result handlers
Mybatis will give you control of actual jdbc result set. So, you can do/iterate over the result one by one here itself.
See this blog entry for more details.

setParameterList list with huge data

I have an Integer array list with 8000 items in it.
And i set that array list in hql using setParameterList method.
Just an example query
return (Integer) sessionFactory.getCurrentSession().createQuery("update data where Id in (:list)").setParameterList("list", arrayList).executeUpdate();
but after executing the query i got this error.
java.lang.StackOverflowError
at org.hibernate.hql.ast.QueryTranslatorImpl$JavaConstantConverter.visit(QueryTranslatorImpl.java:585)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:64)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:65)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66)
at org.hibernate.hql.ast.util.NodeTraverser.visitDepthFirst(NodeTraverser.java:66)
is there any way to solve this issue in hibernate. may be this will work with pure sql query. But i just want to know is there any other way in HQL.
If your list comes from another SQL query, try using WHERRE EXISTS instead.
Otherwise, you might have to update each element independently inside a loop.
IN clause on thousands of items is usually not well handled by databases.
This issue seems to be covered by the documentation. The authors recommend doing this kind of operation in batches.
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html
Your query isn't a valid HQL query. You missed a set clause in the query:
update Data set foo = 7 where id in (:list)
That said, 8000 IDs in an in clause is a lot. Databases have limits on the size of a query. Oracle for example doesn't accept more than 1000 elements in an IN clause.

Hibernate Criteria Limit mechanism?

Hibernate Criteria support provides a setMaxResults() method to limit the results returned from the db.
I can't find any answer to this in their documentation - how is this implemented? Is it querying for the entire result set and then returning only the request number? Or is it truly limiting the query on the database end (think LIMIT keyword as in mySql).
This is important because if a query could potentially return many many results, I really need to know if the setMaxResults() will still query for all the rows in the database (which would be bad).
Also - if its truly limiting the number of rows on the database end, how is it achieving this cross-db (since I don't think every rdbms supports a LIMIT functionality like mySql does).
Hibernate asks the database to limit the results returned by the query. It does this via the dialect, which uses whatever database-specific mechanism there is to do this (so for SQL Server it will do somthing like "select top n * from table", Oracle will do "select * from table where rownum < n", MySQL will do "select * from table limit n" etc). Then it just returns what the database returns.
The class org.hibernate.dialect.Dialect contains a method called supportsLimit(). If dialect subclasses override this method, they can implement row limit handling in a fashion native to their database flavor. You can see where this code is called from in the class org.hibernate.loader.Loader which has a method titled prepareQueryStatement, just search for the word limit.
However, if the dialect does not support this feature, there is a hard check in place against the ResultSet iterator that ensures Java object (entity) results will stop being constructed when the limit is reached. This code is also located in Loader as well.
I use both Hibernate and Hibernate Search and without looking at the underlying implementation I can tell you that they definitely do not return all results. I have implemented the same query returning all results and then changed it to set the first result and max results (to implement pagination) and the performance gains were massive.
They likely use dialect specific SQL for this, e.g. LIMIT in MySQL, ROWNUM in Oracle. Your entity manager is aware of the dialect that you are using so this is simple.
Lastly if you really want to check what SQL Hibernate is producing for this query, just set the "show_sql" property to true when you create your entity manager / factory and it spits out all the SQL it is running to the console.
HQL does not suppport a limitation inside a query like in SQL, only the setMaxResults() which you also found.
To find out if it transform the setMaxResults() into a LIMIT query, you can turn on your SQL logging.
I know Question is bit old. But yes setMaxResults() is truly limiting the number of rows on the database end.
If you really look into your Hibernate SQL output, you can find the following SQL statement has been appended to your query.
limit ?

how to get column metadata in mybatis

I need to get the list of columns in a table using mybatis/ibatis in java 1.5.
That's not a typical requirement (99.99% of applications using iBatis or whatever ORM knows the DB schema). iBatis is a SQL mapper, you must write the SQL query yourself. And there is no standard SQL query (AFAIK) that gives you the number of columns in a table.
I can only suggest two approaches:
Make a SQL query selecting from the catalog tables. That's the normal way of knowing about your DB metadata. But that depends on your particular database engine. And it's not related to iBatis.
QUick and dirty: make an ad-hoc query SELECT * FROM MYTABLE LIMIT 1 (replace LIMIT for your DB analog), map that in iBatis through a HashMap, and in your DAO just count the number of keys.
For Mybatis:You need to use resultType instead of resultmap.
resultType must be of returning collection data type, by knowing the size of collection you can get no. of columns and more over if you are going with HashMap you can get column names too in keys.

Categories

Resources