Hibernate update is sometimes not working - java

I have a requirement where I am updating rows according to uuid's where one uuid may be associated to more than one rows.
Here's the scenario:
4a90558c-4a5b-4af7-8c68-60ff81f74ef3 is my uuid and it exists in 8 columns in my DB.
and my java code is as follows:
try{
session = sessionFactory.getCurrentSession();
tx = session.getTransaction();
criteria = session.createCriteria(Archive.class);
criteria.add(Restrictions.eq("bagUuid", "4a90558c-4a5b-4af7-8c68-60ff81f74ef3"));
ScrollableResults items = criteria.scroll();
while ( items.next() ) {
Archive archive = (Archive)items.get(0);
archive.setDecision(1);
archive.setOperatorAssigned("test");
session.saveOrUpdate(archive);
session.flush();
session.clear();
}
tx.commit();
LOGGER.info("Archive Record is updated: "+archive.getFilePath());
}catch(Exception e){
recordUpdated = false;
tx.rollback();
LOGGER.error("Archive Record failed to update due to exception in updateArchiveRecord method: "+e.getMessage());
}
Here sometimes all records associated to UUID is updating but sometimes failing.
I think it may be a issue with the Hibernate API.
Does anybody else has faced the same issue.

This line looks suspicious:
Archive archive = (Archive)items.get(0);
It means thart regardless of the number of items in the ScrollableResults, you will be updating only the first Archive object. If I understood what you are trying to do correctly, it should be a current record:
Archive archive = (Archive)items.get();
Also, I'd move out/delete session.flush() and session.clear(). The final code would look like this:
try{
session = sessionFactory.getCurrentSession();
tx = session.getTransaction();
criteria = session.createCriteria(Archive.class);
criteria.add(Restrictions.eq("bagUuid", "4a90558c-4a5b-4af7-8c68-60ff81f74ef3"));
ScrollableResults items = criteria.scroll();
while ( items.next() ) {
Archive archive = (Archive)items.get();
archive.setDecision(1);
archive.setOperatorAssigned("test");
session.saveOrUpdate(archive);
}
tx.commit();
session.close();
LOGGER.info("Archive Record is updated: "+archive.getFilePath());
}catch(Exception e){
recordUpdated = false;
tx.rollback();
LOGGER.error("Archive Record failed to update due to exception in updateArchiveRecord method: "+e.getMessage());
}
Slava Imeshev

Related

Java List can not retrieve over 90.000 elements

I am dealing with an issue when I attempt to retrieve a large amount of records from a database. It seems that when the amount of records exceed 90.000, the elements can not be retrieved.
When that happens I get the following exception:
com.sun.jdi.ObjectCollectedException occurred while retrieving value.
The code that I am using is the following one:
Session objSession;
List<GroupEntity> colResults;
objSession = this.objSessionFactory.openSession();
try
{
objQuery = objSession.createQuery("FROM GroupEntity WHERE (strDomain = :Domain)")
.setParameter("Domain", strDomain)
.list();
}
catch (Exception objException)
{
throw new GroupException("Could not retrieve the list of WebFiltering groups to scan");
}
objSession.close();
return colResults;
I attempt to page the results retrieved by sets of 1.000, using this method when I insert up to 89.999 records the list is fine. however when I exceed 90.000 I get the same exception.
Any idea about how to face this issue?
In case you process such a big amount of data I'd recommend that you use batch processing with ScrollableResults: https://grokonez.com/hibernate/resolve-hibernate-outofmemoryerror-problem-hibernate-batch-processing
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
ScrollableResults dataCursor = session.createQuery("FROM Data").scroll();
int count = 1;
while (dataCursor.next()) {
Data data = (Data) dataCursor.get(0);
String newText = Utilities.generatedRandomString();
data.setText(newText);
session.update(data);
if (count % 50 == 0) {
System.out.println("============================log: count = " + count);
session.flush();
session.clear();
}
count++;
}
tx.commit();
} catch (Exception e) {
if (null != tx) {
tx.rollback();
}
} finally {
session.close();
}
In this case session will not keep all 90000 records in memory.
"com.sun.jdi.ObjectCollectedException" happens when the object you referring to is garbage collected.
there is no such limit of size on java arrayList.

Hibernate not getting changes from database even I turn off the session everytime and turn off the 2nd level cache

I have a hibernate fetch as follows (it is called by a synchronized method in threads). The problem is if I updated the status_id to 1 in the DB console, the code won't pick it up. And when I run the sql Hibernate show_sql printed out in the console, it can find one record. Moreover, I can see the select sql being run every time via show sql.
To make the problem clear, if I update the record status to 1 and then start the application, the code will return me one record and after processing, the record status will be updated to 2. As I expected, after that, the code will return nothing cause the status being updated to 2. However, if I manually update the status to 1, it won't pick it up.
As you can see from the configuration, I have already turn off the 2nd level cache and every time, I close the session. I am using Enum to define the Hibernate connection. So the sessionFactory is always the same instance. I don't know if this matters but I assume that is what it should be.
The dao code is
Session session = null;
String sql = "from MyEntity rr where status_id = 1;"
try {
session = getSessionFactory().openSession();
Query q = session.createQuery(sql);
q.setMaxResults(1);
List resultList = q.list();
if (resultList.isEmpty())
return null;
return (MyEntity) resultList.get(0);
} catch (Exception e) {
LOGGER.error(e.getMessage());
} finally {
if (session != null) {
session.close();
}
}
return null;
The code to update the status is
Session session = null;
try {
session = getSessionFactory().openSession();
session.beginTransaction();
session.update(myEntity);
session.flush();
session.getTransaction().commit();
} catch (Exception e) {
LOGGER.error(e.getMessage());
} finally {
if (session != null) {
session.close();
}
}
If the entity doesn't exist, you need to invoke save() on it, otherwise you need to invoke update(), it will modify the existing persistent object in database.
Be aware everytime invoke save() would insert a new row in database. You may use saveOrUpdate() to achieve above save() and update() actions, Hiberate will either call save or update depends on the situation and take care of it.
You can invoke flush() after each saveOrUpdate() which forces Hibernate execute save or update in your database.
I found the solution. Once I put the transaction on fetch, it start to work. Don't know why. Any one can give some explaination? Thanks.

Hibernate Save Java Collection in a single shot

We use Hibernate 5 and we need to persist upto 1 million of records every day, right now code we use is
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
try
{
session.getTransaction().begin();
for (CustomObject customObject : CustomObjectList)
{
session.save(customObject);
}
log.info("Saved all entities in Hibernate Session");
session.getTransaction().commit();
}
catch (HibernateException e)
{
log.error("HibernateException :{}", e.getMessage(), e);
session.getTransaction().rollback();
session.clear();
}
finally
{
HibernateUtil.closeSession(session);
}
Here CustomObject is my Table Entity, so my CustomObjectList contains 1 million records and persisting into Database using default bulk insert property
Can we persist all list values in a single shot instead of iterating , What is the best way to improve performance?
Is Something like session.save(customObjectList) possible?

how to update the table in java using hibernate without using hql and sql

I have tried a lot to update my table using hql but i didn't find the solution , i have searched on internet too, I am new in java and hibernate please help me to find the solution.
my code is written below.
session.getTransaction().begin();
Query query = session.createQuery("update DocDetail set DocName = :docname" +
" where Id = :docId");
query.setParameter("docname", "Jack");
query.setParameter("docId", 3);
int result = query.executeUpdate();
session.getTransaction().commit();
but I got the following error.
Exception in thread "AWT-EventQueue-0" org.hibernate.QueryException: query must begin with SELECT or FROM: update [update clinic.entity.DocDetail set DocName = :studentName where Id = :studentId]
at org.hibernate.hql.classic.ClauseParser.token(ClauseParser.java:106)
at org.hibernate.hql.classic.PreprocessingParser.token(PreprocessingParser.java:131)
at org.hibernate.hql.classic.ParserHelper.parse(ParserHelper.java:51)
If you are using hibernate, you should try to access entities not tables.
The biggest advantage of hibernate is that it provides you ORM (object relational mapping).
Here is the example how to update an entity with hibernate
(of course corresponding table is also updated).
/* Method to UPDATE salary for an employee */
public void updateEmployee(Integer EmployeeID, int salary ){
Session session = factory.openSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
Employee employee =
(Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
}catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
You are creating a Native(SQL) query using createQuery() method instead of createSQLQuery() method so just change your code as follows
session.getTransaction().begin();
Query query = session.createSQLQuery(
"update DocDetail set DocName = :docname" + " where Id = :docId");
query.setParameter("docname", "Jack");
query.setParameter("docId", 3);
int result = query.executeUpdate();
session.getTransaction().commit();
read about about this in detail:
Different ways to create query
Difference between createQuery and createSQLQuery
hope this will solve your problem
To update object without SQL or HQL you can use next code snippet.
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
sess.update(yourObject);
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
Read documentation about update - possible you have to use merge or saveOrUpdate.
Here a way of updating data into table using hibernate hql:
Configuration cfg = new Configuration();
cfg.configure("HibernateService/hibernate.cfg.xml");
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
Transaction t = session.beginTransaction();
String hql = "UPDATE Userreg SET uname = :uname, uemail = :uemail, uphone = :uphone WHERE uemail = :uemail";
Query query = session.createQuery(hql);
query.setParameter("uname", uname);
query.setParameter("uemail", uemail);
query.setParameter("uphone", uphone);
int rr = query.executeUpdate();
t.commit();
if (rr != 0) {
return true;
} else {
return true;
}
you can use hibernate session's merge.
such as
User user = session.find("1");
//get Persistence entity``String userName = user.getUserName(); // userName = "enzo"
//user.setUserName("leo");
session.merge(user);
// Test entity user's useName
String userNameNew = session.find("1").getUserName; // now userName is "leo"
I hope can help you;

Hibernate's Criteria query makes Tomcat become not responive after a few request services

I am running a Spring + Hibernate web application on Tomcat 7.0.35 (Spring 3.1, Hibernate 3.6.1, JPA 2.0).
This app has a page that gets data from the database via Hibernate's Criteria (I know I dont have to). The service tier simply calls the data tier. Here is the code:
Criteria criteria = sessionFactory.openSession().createCriteria(Article.class);
criteria.addOrder(Order.desc("updatedTime"));
criteria.add(Restrictions.eq("account", acc));
criteria.add(Restrictions.eq("draft", true));
criteria.setMaxResults(1);
Article s = (Article) criteria.uniqueResult();
return s;
Tomcat can only serve a few requests from this page, and then it becomes non-responsive. I can see the browser keeps waiting for server response (Firefox status bar shows "waiting for host".)
I am not seeing any error message such as OutOfMemory, etc. It appears that the browser waits forever.
If I change it to JPA as follows:
#NamedQuery(name = "Article.getMostRecentDraftArticle", query = "select x from Article x where x.account = :account and x.draft = 1 order by x.updatedTime desc"),
.....
Query q = getSession().getNamedQuery("Article.getMostRecentDraftArticle");
q.setParameter("account", acc);
q.setMaxResults(1);
List list = q.list();
if (list.size() == 0)
return null;
else
return (Article) list.get(0);
Then everything works right.
What could go wrong with my use of Hibernate's Criteria API?
Thanks for any input!
Cheers.
You haven't closed the session. See this answer: https://stackoverflow.com/a/4049758/116509
and read the javadoc of org.hibernate.session:
A typical transaction should use the following idiom:
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
//do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
Can you see the hibernate logs? does it generate the query?
Anyway, you can try to put a sessionFactory.getCurrentSession().flush(); below Article s = (Article) criteria.uniqueResult();

Categories