Querying Hibernate cache - java

I have the following code:
Person a = new Person();
a.setName("John");
Session session = openHibernateSession();
session.beginTransaction();
session.saveOrUpdate(a);
Criteria critera = session.createCriteria(Person.class);
critera.add(Restrictions.eq("name","John"));
Person personFromCache = (Person) criteria.uniqueResult();
...
session.commit();
What I want is to have the ability to search objects from both the database and Hibernate's cache. The following example returns null upon calling uniqueResult. Is there any way to retrieve saved objects that have not yet been committed to the database?

If you are searching other than ID then Hibernate will not use first level cache. Hibernate get and load is related to first level cache by default but criteria query is not. In your case there are two solution from my side
By flushing session = Just flush your session like this session.flush(); while doing so data from session will be synchronize to database hence Id will ge generated and as result Criteria query will find the result in database and will result list to you.
Enable hibernate second level cache = You can enable second level cache by hibernate cache providers like ehCache and apply the trick.

You can use the StatelessSession but be warned:
those entitys are not bound to any session and you will get Exceptions if you like to resolve relations or lazy fields!

session.beginTransaction();
session.saveOrUpdate(a);
session.flush();
Criteria critera = session.createCriteria(Person.class);
critera.add(Restrictions.eq("name","John"));
Person personFromCache = (Person) criteria.uniqueResult();

We do some similar things except using TestNg test framework. Several of the answers discuss the session.flush() method call. This is correct. The call to flush tells Hibernate to do several things, including making sure that all database calls currently waiting in the queue get executed and cleared from the queue.

It returns data even if you are selecting on the basis of username. It is not returning null.

Related

Hibernate second level cache - multiple objects of the same entity

I need to ensure that only one object of the same entity is created (as it is done when loading data using first level hibernate cache, to simplify entity refreshing) and I want to use second level cache.
Im testing ehcache but cant make it working. Normally the entities in my app are being nested in other entities but this is just an simple example of usage:
a) example using first level cache which works fine:
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.getTransaction();
transaction.begin();
Person person=session.get(Person.class, 1L);
Person person2=session.get(Person.class, 1L);
transaction.commit();
session.close();
System.out.println(person2 == person);
and it returns true
b) using second level cache with Ehcache
//1. load person with id 1
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.getTransaction();
transaction.begin();
Person person=session.get(Person.class, 1L);
transaction.commit();
session.close();
//2. load the same person
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.getTransaction();
transaction.begin();
Person person2=session.get(Person.class, 1L);
transaction.commit();
session.close();
System.out.println(person2 == person);
and it returns false
Is it normal behaviour of second level cache to be like that or do i miss something?
Does any second level cache engine keep only one instance of the same entity (as first level cache do)?
This is not possible to keep one instance of the entity in RAM in Hibernate using second level cache as each time Hibernate find it in the cache, it just creates new instance based on the cached data.
For my purpose I have implemented AVL Tree based loaded entities and database synchronization engine that creates repositiories based on the loaded entities from hibernate and asynchronously search throught all the fields in entities and rewrites/merge all the same fields (so that if some field (pk) is the same entity like the one in repository, it replaces it)
In this way synchronization with database is easy as it comes to find the externally changed entity in the repository (so basically in the AVL Tree which is O(log n)) and rewrite its fields.

Set timeout based on query

How to set up a timeout for some specific queries using Java or Hibernate. The problem I am facing is that some queries where I have to fetch large amount of data some times do not respond for longer periods resulting in an unresponsive application.
Hibernate query has setTimeout() method
Query query = session.createQuery(someQueryString);
query.setTimeout(theTimeOut);
JPA standard property javax.persistence.query.timeout can also be provided as a "hint" to each query.
query.setHint("javax.persistence.query.timeout", someTimeout);
Hence avoiding tying your code to one JPA provider or another.
Hibernate supports Transaction time outs:
//set transaction timeout to 5 seconds at session
Session sess = factory.openSession();
sess.getTransaction().setTimeout(5);
You can also setup at query level.
Query q = sess.createQuery("from....")
.setTimeOut(3);

Hibernate multiple object update in same session

Using Hibernate I need to update multiple objects by calling for eg. updateDetails() function shown below:
function updateDetails(){
Session session = this.getSessionFactory().openSession();
Employee emp=(Employee )session.load(Employee.class, empId);
emp.salary(2000);
Account acc=(Account)session.load(Account.class, accId);
account.setTotal(2000);
Transaction tx=session.beginTransaction();
session.update(emp);
session.update(acc);
tx.commit();
result=true;
session.close();
}
what is the best way of doing this ?
does Updating multiple objects of same or different type in same session will cause any problem in hibernate?
Why not. You can do that. Hibernate allows.
Since you are using Transaction management the answer is depends on your context. If you want to save both Objects regardless of saving another make them update in individual transactions.
If you want to save the whole info successfully and want to revert everything if any of the update fail keep them in the current format.

Java Hibernate JOIN with a inner Criteria throws no session or session was closed

i have written a small piece of code like this. i need all the students and they phones in a one to many relationship.
public ArrayList<Student>getListOfStudents()
{
Session session = getHibernateTemplate().getSessionFactory().openSession();
Criteria like = session.createCriteria(Student.class).setFetchMode("phone",FetchMode.JOIN).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
prepareForSelect(like);//some filtering
like.addOrder(Order.asc("name"));
ArrayList<Student> results = new ArrayList<Student>(like.list());
session.close();
return results;
}
this is working very good but i need to tweak it because i need to implement the same criteria filtering in phone as well i have redesign my snippet to something like this.
public ArrayList<Student>getListOfStudents()
{
Session session = getHibernateTemplate().getSessionFactory().openSession();
Criteria like = session.createCriteria(Student.class).setFetchMode("phone",FetchMode.JOIN).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
prepareForSelect(like);//some filtering
Criteria innerCriteria = like.createCriteria("phone");
prepareForSelect(innerCriteria);//same filtering but in phone now..
like.addOrder(Order.asc("c01"));
ArrayList<Student> results = new ArrayList<Student>(like.list());
session.close();
return results;
}
but hibernate has changed from left outer join to a inner join and when i run the data in the same methods the before code was running i can see a error is throw.
Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.generic.model.Student.phone, no session or session was closed.
my question is what i am doing wrong how can i apply the filters and get the joins correctly thanks a lot.
Well, the problem is that the phones of a student are not eagerly fetched. And since you are closing the session, when you are try to access the phones you are getting LazyInitializationException.
But you are asking yourself I had set the fetch mode to eager by using setFetchMode("phone",FetchMode.JOIN) and it was working just fine. The thing is, there is a bug in Hibernate which disables eager fetching when you add an inner query to a criteria. It is still open. See here:
https://hibernate.atlassian.net/browse/HHH-3524
And if you have time you can take a look at here:
https://forum.hibernate.org/viewtopic.php?f=1&t=944439
If you do, make sure you read the second page, it gets funnier.
So my suggestion is to make the fetch eager at the class level, by using fetch=FetchType.EAGER or switch to CriteriaBuilder (JPA).

Update specific field of table regardless of other fields in hibernate

I have table having lot of information. I am not loading all the information while updating this table from view page.
Below is my code to update the table using hibernate
HibernateTemplate hibernateTemplateObj = getHibernateTemplate();
hibernateTemplateObj.update(myEntityBean);
Above one was updating the fields but the fields which are not visible on my view page will be updated with blank.
So, I used below one...
HibernateTemplate hibernateTemplateObj = getHibernateTemplate();
hibernateTemplateObj.update("myRequiredField", myEntityBean);
As per documentation here it says if I use update("string",entity) it will update that fields. But it's not working as same.
Can any one please suggest something.
I found some posts.
post1
post2
It says, I need to create queries. But I don't know how to create queries from it?
If any one have any idea.. Please help. I think it's known issue from those posts.
You can create a query with the Session object like this.
SessionFactory factory= HibernateUtil.getSessionFactory();
session = factory.openSession();
session.beginTransaction();
Query query = session.createQuery("Select c.productList from Cart c Where c.cartId=:cartId");
query.setParameter("cartId", cart.getCartId());
List productList=(List) query.list();
session.getTransaction().commit();
While you know what kind of object should return from query you can cast it and use it.
You can write native query or hibernate query but I think hibernate query is easier.

Categories