Hibernate getOne() not working with background thread - java

There is a scenario I have encountered, where I'm returning the API response(request thread) and delegating the task to a background thread.
In the background thread, I'm calling hibernate's T getOne(ID id); to fetch some information, which is resulting in
org.hibernate.LazyInitializationException: could not initialize proxy - no Session in Thread class
But, when performing DB operations with JPA queries #Query("some query"), native query #Query(value = "some query", native = true) and JdbcTemplate, it's working fine in the background thread.
Can someone help me understand why such behaviour?
FYI.. I'm using Spring Boot 1.4.2 and Hibernate 5.0.11

T getOne(ID id) relies on EntityManager.getReference() that performs an entity lazy loading. So to ensure the effective loading of the entity, invoking a method on it is required.
Basically your thread is unable to find any active sessions context.Hibernate throws the LazyInitializationException when it needs to initialize a lazily fetched association to another entity without an active session context.
You FetchType.EAGER in any of the associations you are having w.r.t to the object you are trying to get. But, it can have its own repercussions like unwanted query execution every time you try to get object.
Best Solution will be using Optional<T> findById(ID id) You can get check if entity exists using obj.isPresent() and continue.

Related

Does Session.getCurrentSession() closes without doing any transaction?

I am trying to load entity by doing this:
public void reloadRepository() {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
Hibernate.initialize(Repository.class);
}
From this stack overflow post (Hibernate openSession() vs getCurrentSession()), it says
When you call SessionFactory.getCurrentSession, it creates a new
Session if it does not exist, otherwise use same session which is in
current hibernate context. It automatically flushes and closes session
when transaction ends, so you do not need to do it externally.
What does it mean by "transaction ends"? If I don't make any transaction (guessing Hibernate.initialize() is not making transaction), does hibernate close this session?
Probably.
I'm guessing you set current_session_context_class to thread (since you're using beginTransaction). This means that, according to the javadoc, the session is only usable after transaction is started and is destroyed automatically when transaction ends.
I'm not sure what you mean by 'not making any transaction', you just made one using beginTransaction(). Once you commit or rollback, the transaction will end. Even if you do neither, the transaction will eventually time out,and that will also count as ending the transaction.
It's written like that because in modern apps you control transactions with the #Transactional annotation. You simply put it on top of the service methods and Hibernate opens a transaction automatically and closes it when it reaches the end of the method.
I don't really know what you think your last row of code is doing but it looks very wrong. If you want to load an entity you can simply write session.get(), add #Transactional to your method and delete session.beginTransaction() and Hibernate.initialize().

Spring Data Jpa - cache

Hello my problem is that i can't avoid cache. I'm using Spring Data Jpa with Spring Boot 1.5.4
What am I doing:
I have a case when some client request my REST endpoint with some data based on which I am creating an entity and I'm saveing it into database, next I request another REST endpoint which response me dirlectly OK, but request which I got isn't finished yet. Next I'm waiting for another service which has to request my another REST endpoint (First client is all the time on wire). This endpoint modifies entity which was created after first request I got and here I got problem.
So basicly, first request creates entity and saves it using "saveAndFlush" method. When first request is waiting another thread modifies this entity using spring data jpa:
#Modifying(clearAutomatically = true)
#Query("UPDATE QUERY ")
#Transactional
int updateMethod();
But after that (when first request is released from waiting) when I call findOne method in first thread I got old entity, I have tried also override method:
#Transactional
default MyEntity findOneWithoutCache(Long id) {
return findOne(id);
}
But this not working too, I also added
#Cacheable(false)
public class MyEntity {
And this is not working too.
There is only one way which is working, when i select this entity using #Query this way:
#Query("SELECT STATEMENT "
+ "WHERE p.id = ?1")
MyEntity findEntityById(Long id);
Could you explain me how to solve this problem?
The thing is what kind of Transaction Isolation do You have?
What Database , settings, driver?
Theoretically in a perfect ACID transaction - after starting transaction you cannot see changes done in other transactions. (see Repeatable Read).
On the other hand typically you do not have I in ACID. And isolation is weaker.
(like Read Commited).
If the query works it suggests you do not have Repeatable read - so maybe you should simply get EnityManager (via JpaContext) and try to clear() session (in the 1st thread)?

Spring #Transaction (readonly=true) context commit data to DB in the middle of the process

I am working on an assignment to make the code transactional. I am having this problem about read-only transaction for while and none of a single suggestion I found on the internet didn't work. (Spring and hibernate integrated project)
This is my read-only transactional method
#Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=true
,rollbackFor=Exception.class)
public void
editInternationalExportConsigment(InternationalExportConsignmentFormWrapper
exportConssi (){}
Inside this method, there is a translator process happening. Where the process fetch (select ) data from DB and set to an Object
Contact contact =inquiry.loadCustomerContactById(consignmentVO.getCustomerContactId().intValue());
if (contact != null && contact.getCity() != null) {
consignment.setOrgin(contact.getCity().getCountry());
consignment.setUniqueOriginCountry((contact.getCity().getCountry()!=null)?contact.getCity().getCountry().getId():null);
consignment.setOrginCity(contact.getCity());
}
There are no any update or insert query run in the middle, Only select. But end of the this code snippet execution it commit the data to DB (whatever the value set to setter method will persist into DB )
Can someone please tell me what wrong is happening here. your feedback will be much appricated.
After tedious research, I have found the answer. In our project there are two session factories are running. And also it uses spring OpenSessionInViewFilter to avoid 'lazy initializing' issue. OpenSessionInViewFilter has set flushMode to Auto. Since the OpenSessionInViewFilter keeping binding a hibernate session to the thread along in the entire process, it will override the transactional hibernate session object which gets creates once I start the new transaction.Therefore even if I kept the flushmode for transactional scope as 'COMMIT' it get override with the AUTO property by the properties declared OpenSessionInViewFilter.
When the flushMode is AUTO hibernate will flush dirty objects to DB.
Read this for understand hibernate data flushin
As a solution, I manually change the flush mode to 'COMMIT' inside my transactional method.
Thank you for everyone replied and commented. :)

Spring Data JPA - changes are not visible outside the environment/application

I am using Spring data jpa to store and read entities across diffferent applications. Below are the steps that are executed:
Application 1 creates an entity via jpa repository and stores it into db with saveAndFlush() method
It then sends an event to queue saying, entity is created
This event is then read by another application (let's say Application 2) which then tries to read the entity and processes it
Following is the example method used to store the object:
#Transactional
public Entity createEntity(final Entity entity) {
return entityRepository.saveAndFlush(entity);
}
As per the documentation, #Transactional annotation should make sure the object gets persisted once method execution is finished. However, when Application 2 receives an event and tries to look up the entity (by id), it is not found. I am using Maria DB and Spring Data JPA 1.9.4.
Do we need to do anything else to force hard commit after saveAndFlush call?

Java Hibernate OpenSession in View Avoid fetch on Controller

we have a APP in Hibernate lately we start using Open Session in View in our DAO we fetch the data we really need.. we dont close the session but later in our controller in any operation on the Entity Hibernate is fetching the Data from the DB i know this behavior is the main reason to use open session but i dont need the fetch is some cases.. i was wondering if i can tell hibernate not fetch the data in some cases....
student.getSchool().getTeachers()
in this case i have load all the data i need from this 3 entitys but hibernate starts to load the school and the teachers again..
thanks a lot
Three main options:
If you use EH-Cache, you won't have to wait while Hibernate queries the database for Student & School again.
Or you could keep the form & Hibernate Session in the HTTP Session, which also achieves caching.
For AJAX or similar requests fetching just the Teachers, you could change the Criteria to Projection or use a Hibernate Query, to "project" or retrieve just the target entity.. at the database level, doing a joined or sub-expression query. Student would be loaded but only as a proxy, in this case.

Categories

Resources