Flushing Session in Services - java

Maybe it is my misunderstanding of Hibernate's Session flushing but I have been thinking in flushing my session inside my services but It does not feel ok to make things like this in a service:
public Object serviceMethod(Object model){
//Do things with model
sessionFactory.getCurrentSession().flush();
}
It feels wrong because my services will be knowing about my persistence mechanism.
So I have been thinking about making an aspect and using annotations so my code looks like this:
#FlushAfter
public Object serviceMethod(Model model){
//Do things with model
}
Is this approach correct or am I doing things the wrong way?

There is no need to do that, as it's done automatically by the transaction interceptor already: by default, a Hibernate session is flushed automatically before the transaction commits. So if your service is transactional (and it should be, to work with Hibernate), the session will be flushed automatically.

transaction interceptor/manager might decide to flush session() at the end of the transaction. Also remember that it may automatically flush session in the middle of the transaction if required. you don't have call flushsession explicitly. By the way, what is the reason to call flush session explicitly.
This flush session in the middle of transaction - related question on this topic

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 #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. :)

Hibernate flush_before_completion work like post flush or pre flush?

I have an Hibernate Interceptor that implement a postFlush(). From my understanding, post flush is the data has been saved into database but it is subject to rollback before commit is invoke. If I have a hibernate configuration that look something like this:
<property name="hibernate.transaction.flush_before_completion">true</property>
Do this means save data into database before commit? Which is the same thing as post flush? Will this cause the hibernate interceptor postFlush() call during pre flush stage?
The property hibernate.transaction.flush_before_completion is used for "Container Managed Transaction (CMT)" or JTA, if you're using JDBC Transactions it is not relevant.
If set to true, a flush will be performed during the before completion phase of the transaction, sending all data to the database (a rollback is still possible). This flush is not managed by the hibernate session.
If set to false the automatic session managed flush of hibernate is executed before the commit and consequently the postFlush will be called.
The postFlush() method of the Hibernate Interceptor will only be called after the hibernate managed Flush is executed and before the transaction is committed.

Get Hibernate Session from Interceptor

I'm writing a hibernate interceptor and I need to access the hibernate session object. Is their a direct way to access the hibernate session using the interceptor?
What I'm trying to do is to find out what database hibernate has connected to. For various reasons, this is going to be impractical to store as thread local data.
Yes, there is a way... just pass session to Interceptor after creation:
Session session = factory.openSession(interceptor);
interceptor.setSession(session);
And you have session inside interceptor! Just remember that:
Interceptor can't access session it's running in, so don't use it directly to change / add objects.
You can open temporary session on the same JDBC connection
Transaction will be the same for both sessions
try {
Connection connection = mySession.connection();
Session tempSession = HibernateUtil.getSessionFactory().openSession(connection);
// do something
tempSession.flush();
}
finally {
tempSession.close();
}
There seems no "official" way of getting hold of the session object neither through o.h.Interceptor neither through o.h.EmptyInterceptor. Moreover, Interceptor's Javadoc says:
There might be a single instance of Interceptor for a SessionFactory,
or a new instance might be specified for each Session. Whichever
approach is used, the interceptor must be serializable if the Session
is to be serializable. This means that SessionFactory-scoped
interceptors should implement readResolve().
The Session may not be invoked from a callback (nor may a callback
cause a collection or proxy to be lazily initialized).
The only way to get this information seems to be by using reflection and has been answered here.

Hibernate error "database is locked". How do i correctly close session?

In my application I open session, create criteria but dont close it. Then in other method I open session again, update object and receive database is locked on tr.commit().
If I put session.close() in first instance I receive
could not initialize proxy - no Session.
How do I close and open sessions correctly? Or do I need to copy proxy objects to those created by me and then close()?
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tr=session.beginTransaction();
Criteria criteria = session.createCriteria(MyDocument.class);
criteria.add(Expression.like("isMainDoc", 1));
List docs = criteria.list();
tr.commit();
session.close();
I am a complete begginer. i use sqlite. Any help would be appreciated. Thanks in advance.
Hibernate Session is generally tied to a thread.
So, perhaps you should restructure your code to get a session at the beginning of your processing (e.g. in ServletFilter instance of a web-app).
And then in each method, you can use the same session object, to start a new transaction (and then of course, end the transaction also.
public void doWork(){
Transaction tx = null;
try{
tx = session.beginTransaction();
}catch(){
} finally {
// if tx != null then.. close transaction, or rollback?
}
}
EDIT: And then ofcouse, close the session when the processing is done (in web-app, that could be also in the same ServletFilter)
Google: "Open Session In View" pattern.
Cause
You might be getting the error when you are trying to access properties of the MyDocument class instances returned by the query.
Hibernate is lazy by default. It returns you a proxy for an object instead of hitting the database whenever a reference property is accessed. This behavior can be overwritten whenever required.
Always remember that could not initialize proxy - no Session is recieved when the code tries to access a proxy properties (by hitting the database) and finds that the session is not available ( Session is needed as Hibernate accesses database using this interface)
Solution
Make sure that your session is open whenever Hibernate tries to load object which have not been loaded yet. How do you do that?
(In simple words) There are two schools of thoughts in Hibernate:
Fetch all the data that you might access before you close the Session OR
keep the Session open for the entire duration of time you work on the objects.
I would like you brush up topics such as the unit of work in Hibernate. Hibernate provides a wonderful interface to define boundaries on database access. Data must be accessed (read/written) between these boundaries. Check Here
hibernate.current_session_context_class in the hibernate configuration which can take the values jta | thread | managed | custom.Class. This variable defines the unit of work for your Session.
Last but most importantly try using Contextual Sessions (you must have come across .getCurrentSession()
which helps you to get the same session which is open everytime anywhere in your code. Hibernate handles everything behind the scenes.
Hope this answer serves as a guide for you for taking the correct path in using Hibernate rather than just solving this particular problem.
Follow the below steps when you are using hibernate transactions Read the API here.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Or any other operation.
session.save(a);
tx.commit();
session.close();

Categories

Resources