How to use update hibernate query using setMaxResults? - java

I hope it is the appropriate section, I have a problem with this code
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("update database set floop= :ctrl1" +" where ctrl= :ctrl2 ").setMaxResults(2);
query.setMaxResults(2);
query.setParameter("ctrl1",3);
query.setParameter("ctrl2", 5);
I ask through setMaxResults(2) to do the update only on the first two and he makes the update of all records as I do what is wrong?? thanks for any help
I thought to use session.createSQLQuery, but I do not know how to do.

This answer is posting delay but it can be helpful for others user who is looking update number of rows in DB with limit using HQL
Unfortunatly setMaxResults() do not work update and delete hibernate
query. It works only select criteria.
As per HQL there is no specific solution is available and you want to update rows with number of limit then follow below steps
Write a HQL to select all rows with condition or range with
setMaxResults. It will return you a List object with limit.
Then update the specific property (Property you want to update) and
store Objects of these rows again by session.update() method.
I'm assuming tablename with map Database class and there are two variable ctrl and floop with getter and setter(as per your question)
List<Database> list = new ArrayList<>();
Transaction transaction = session.beginTransaction();
//Fetching record with limit 2 using setMaxResults()
int setlimit = 2;
String hql_query = "from Database where ctrl = :ctrl2";
Query select_query = session.createQuery(hql_query).setMaxResults(setlimit);
select_query.setParameter("ctrl2", 5);
list = select_query.list();
//iterating list and setting new value to particuler column or property
int result;
if (list != null) {
for (Database element : list) {
element.setFloop(ctrl1);
//Here is updating data in database
session.update(element);
}
result = list.size();
} else {
result = 0;
}
System.out.println("Rows affected: " + result);
transaction.commit();

setMaxResults limits the number of results which are returned by the query, not the number of affected rows.
When you only want to update a limited set of rows, you should specify these rows within the where condition. Setting a hard limit on the number of updated rows wouldn't make much sense, because there would be no way to tell which rows would be updated.

query.setMaxResults(2); will be used for selection queries and will be ignored for insertion/updation. If you use it for selection queries, then you will get 2 records in result.

setMaxResults only applies to select. For your problem I would perform a select query and then use the query.setMaxResults(2), this will return a list of max 2 elements. Then loop the list returned and use session.update for the one or two elements returned.

I can see a number of perfectly valid use-cases where you want to update only a limited number of rows and as other have already answered, the Hibernate Query cannot deal with this so you need to resort to native SQL.
You don't specify in the question which type of database you are using so this answer will only apply to MySql:
Transaction transaction = session.beginTransaction();
Query query = session.createSQLQuery("UPDATE database SET floop= :ctrl1 WHERE ctrl= :ctrl2 LIMIT :max");
query.setParameter("ctrl1",3);
query.setParameter("ctrl2", 5);
query.setParameter("max", 2);
Please note that the sql query above needs to use the native table and column names and not the ones in your ORM model.

Related

The best way to update a millions lines in Java Batch

I devloppe a batch with juste main method in legacy project with : java 7, hibernate and Spring using mysql database.
In this batch I want to update a several lines in a table that have more than 50 millions lines.
When I start the batch each day I have to update at least 10000 lines.
So, what is the best way to update the line without lock the table in mysql ?
Juste do one query like this :
update table items set is_achive = true where id in (id1,id2,id3....id10000)
Or use a for loop like this :
for(item p : ItemsList){
update table item set is_achive = true where id = p.id
}
This depends how you determine the list of rows that need updating. If you query the database to determine the list, it's probably best just to use a DML statement like:
UPDATE Item i SET i.achive = true WHERE ...
If your concern is locking i.e. the amount of time rows are locked, you can use batching by using a cursor e.g. some id of the data source.
SELECT id FROM ... WHERE id >= :start AND ...
ORDER BY id
OFFSET 100 -- use a batch size that suites your needs
LIMIT 1 -- use a batch size that suites your needs
The limit and for update can be implemented by using a query
Integer end = entityManager.createQuery("SELECT id FROM ... WHERE id >= :start AND ... ORDER BY id")
.setParameter("start", previousEnd)
.setFirstResult(100) // batch size
.setMaxResults(1)
.getResultList().stream().findFirst().orElse(null);
Then do a query like this
UPDATE Item i SET i.achive = true WHERE i.id BETWEEN :start AND :end
or if the end is null i.e. the last batch use
UPDATE Item i SET i.achive = true WHERE i.id >= :start
Use Hibernate Criteria builder:
CriteriaBuilder cb = this.em.getCriteriaBuilder();
// create update
CriteriaUpdate<Order> update = cb.createCriteriaUpdate(Order.class);
// set the root class
Root e = update.from(Order.class);
// set update and where clause
update.set("amount", newAmount);
update.where(cb.greaterThanOrEqualTo(e.get("amount"), oldAmount));
// perform update
this.em.createQuery(update).executeUpdate();
https://thorben-janssen.com/criteria-updatedelete-easy-way-to/
It is best to try to get to the root if it like Chris B suggested, but if it's something you can't do, then you might also consider leveraging Spring JDBC Batch Update Operations as documented here. These have existed for some time, so find whichever documentation is appropriate for the version you're using.
https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch12s04.html

Convert HQL query in the form of "select foo from Foo foo, Bar bar where ..." to Criteria query

In our (ancient) project, we use loads of select queries with HQL on Hibernate version 3.5.6-Final. Because Hibernate will do an auto-commit, because it doesn't know they are select queries, I'm in the process of rewriting all HQL select queries to Hibernate Criteria queries so it won't do in-between commits when we don't want it yet. This is pretty straight-forward in most cases, but I'm currently looking at a query like this, and I'm not sure how to transform it:
Query query = session.createQuery("select municapilityStreet"
+ " from MunicapilityStreet munStreet, Street street"
+ " where munStreet.id = street.MunicapilityStreet.id"
+ " and street.id = :streetId");
query.setParameter(":streetId", streetId);
MunicapilityStreet result = (MunicapilityStreet) query.uniqueResult();
return result;
Here what I have thus far in the process of transforming it:
Criteria criteria = session.createCriteria(MunicapilityStreet.class);
// No idea what to set here to only get the "municapilityStreet" as result
criteria.setProjection(??);
// I'm not sure if this is correct. With a criteria on a single table it would have been simply "Id".
// Both tables have the column-name Id, and I'm not sure how to differentiate between them.
criteria.add(Restrictions.eq("Street.Id", streetId));
MunicapilityStreet result = (MunicapilityStreet) criteria.uniqueResult();
return result;
Maybe I should create a different question for each, but converting the above HQL query to a Criteria has three points I'm not sure about how to do:
How to do a select with multiple tables (the from MunicapilityStreet munStreet, Street street part)?
How to have a projection to only return a single table of the two (the select municapilityStreet part)?
How to have an equal-Restriction on a column name of one table, even though both tables have the same column-name (the and street.id = :streetId part)?
I do oppose the rewrite approach, I hope I'm not impolite doing so.
Hibernate allows to control commits (autocommit is by default off), and what you're experiencing are Entitymanager-flushes, they are auto by default and can be disabled too. And, finally, I think, there is no difference if you're running HQL or criteria queries, same machinery underneath.

How to get latest 5 results from MySQL database using Spring,Hibernate

I need some help to fix my issue. I'm having a REST webservices project with Spring and Hibernate. By executing the POST call in POSTMAN,I've inserted some details into MySQL database. So, now i need to get latest 4(which means last 4) from the database table using GET
---id--------|----testname---|----testmethod----|---groupname---|-result----
So, these above mentioned are the columns of my database table. so i need to get last 4 results based on column groupname. So, i need to search by groupnameand id. The values of groupname will be like [Test]. So, can anyone tell is there any way to get those details through GET call.
If you want to retrieve some specific number of rows from database using hibernate then you can do something like this
Criteria cr = session.createCriteria(YourClass.class);
cr.setFirstResult(1);
cr.setMaxResults(4);
List results = cr.list();
The above code will retrieve first 4 rows from your DB.
If you want to retrieve last 4 rows then you have to somehow count the number of rows then use code like this
Criteria cr = session.createCriteria(YourClass.class);
cr.setFirstResult(count-4);
cr.setMaxResults(count);
List results = cr.list();
it will give you last 4 rows from your DB.
if you want to use HQL then you can do something like this
Query q = session.createQuery("FROM table");
q.setFirstResult(start);
q.setMaxResults(maxRows);

Hibernate Criteria API - update many rows with one database query

I'm fetching from database bunch of persons like this:
public List<Object[]> getLimitedBunchOfPersons(Integer limit) {
Criteria criteria = getSession().createCriteria(Person.class, "person")
.setProjection(
Projections.projectionList()
.add(Projections.property("person.personId"), "personId")
)
.createAlias("person.status","status")
.add(Restrictions.eq("status.statusId", 1L))
.addOrder(Order.asc("person.createdOn"));
return criteria.setMaxResults(limit).list();
}
As I needed to speed things up, I only fetched ID's of my entity. Important thing to note is that I'm manipulating with large number of rows and for one query had to use maxResults limitation.
Now my problem is, how to easily update with Hibernate Criteria API in one database query all fetched rows from previously mentioned query?
Plain SQL query would go something like this:
UPDATE PERSON
SET STATUS = 2, CREATED_ON = CURRENT_TIMESTAMP
WHERE STATUS = 1;
It's important to note that update method have to use same order and limit as getLimitedBunchOfPersons() method.
For Single Object it will work as follows after your code
Person per= (Person) criteria.uniqueResult();
per.setCreatedOn("crtBy");
currentSession.merge(per);
Now if comes in list you can iterate list by passing mentioned code in your List iteration

getresultlist - query ok but data duplicate in List

I have a problem with getResultList().
My query is OK when it's executed and return 700 results.
In the return List, I had 700 results but the list contains duplicate data.
So I do not have all results.
public List<EscaleCatalogueKaravel> obtenirListeEscaleKaravelSelonMarche(Integer refMarche, Integer refLangue) {
List<EscaleCatalogueKaravel> listeEscales = entityManager.createQuery("select distinct p from EscaleCatalogueKaravel p " +
"where p.refMarche=:refMarche and p.refLangue=:refLangue group by idEscale ")
.setParameter("refMarche", refMarche)
.setParameter("refLangue", refLangue)
.getResultList();
if (listeEscales == null || listeEscales.size() == 0) {
return null;
}
return listeEscales;
}
Have you got an idea ?
You're using MySQL, right? Oracle would not execute the query but throw an error instead.
For correct usage of the group by clause you're only allowed to select that rows (or expressions) which are also mentioned in the group by clause. If you select a row which is not in the group by clause, this row might have different values for the members of one group. Which of these values the database should return? MySQL arbitrarily returns one of the possible values, but that is not correct.
In your query you either only do select distinct idEscale from ... or you group by all necessary columns and only select that ones or you drop your group by clause. By the way, distinct also can be used without group by, and distinct only should be used if really necessary because it makes the query slow.

Categories

Resources