Does Hibernate 1st Cache work with HibernateTemplate? - spring

I am trying to dive a little deeper into Hibernate cache and Spring's HibernateTemplate, and I am kinda confused by the following questions:
1) How does HibernateTemplate manages the Hibernate session? If I invokes methods such as "getHibernateTemplate().find" and "getHibernateTemplate().execute()", will everytime HibernateTemplate opens a new Hibernate session to process?
2) Hibernate 1st cache works in the scope of Hibernate session. In this regards, if HibernateTemplate always open a new session to exeucte/find, then does it mean the Hibernate 1st cache is NOT usable with HibernateTemplate? (because the cached object will be destroyed anyway, and the next find() has to make a fresh query to get everything again from DB)
3) It seems Hibernate 1st cache holds a map of all objects fetched during the life of a session. In this case, if I query a object which had been fetched before in the same session, then I should get the object and all its data directly from the cache? In this regards, what happens if the data of this object has been modified in the database?
4) Hibernate 1st cache returns the data in format of objects, in this regards, if I use HQL to fetch only a few columns (attributes) from a table (object), will those data (objects with only part of its attributes being filled) also be cached?
Thanks a lot!
-------------------------- Additional Info --------------------------
Thanks to the hint from Alessio, I re-checked the Spring specification and the following is my understanding:
If I call the getHibernateTemplate() within a existing transaction block (e.g., behind "session.beginTransaction();"), then HibernateTemplate will use the existing transaction to execute.
If I call getHibernateTemplate() with no transaction in current thread, then getHibernateTemplate() will actually call "openSession()" instead of "getCurrentSession()" because there is NO transaction (even when openSession() had been called before and an opened session was already bound to current thread), and a new session will be created and given to getHibernateTemplate(). Once the getHibernateTemplate has done its work, the newly created session will be destroyed.
Am my understanding right?

The Spring documentation says the following about session access and creation:
"HibernateTemplate is aware of a corresponding Session bound to the current thread, for example when using HibernateTransactionManager. If allowCreate is true, a new non-transactional Session will be created if none is found, which needs to be closed at the end of the operation. If false, an IllegalStateException will get thrown in this case."
So, whether it creates a new session or not depends on the allowCreate property and the presence of an interceptor that sets up a session for the current thread. Note also that HibernateTemplate is capable of falling back to Hibernate's SessionFactory.getCurrentSession().
-------------------------- Additional Info --------------------------
Edit: to answer to the additional question by the author, the documentation is not very explicit about this, but a session is obtained or created when getSession() is called, which includes calls to execute() of course. A session is not created or accessed in any way when you only instantiate a HibernateTemplate or get it from an application context, as the call to getHibernateTemplate() presumably does.

Related

Context in transactions with Mongoid

I need to use mongoid's transactions to execute some operations while keeping consistency in case of failure.
Following the official documentation, I understand that I have to initiate a session on a model and execute the operations between start_transaction y commit_transaction.
The thing I do not understand is the fact that I have to instantiate a session on a specific model or instance of a model.
I do not get if it is because the model posses a helper to execute that operation (due to beign Monogid::Document) or maybe the operations I have to execute must be related to the model/instance used.
I mean, should I be able to execute this (I understand that is more or less wrong cause these model might be totally unrelated):
ModelA.with_session do |s|
s.start_transaction
TotallyUnrelatedModelA.create!
TotallyUnrelatedModelB.create!
TotallyUnrelatedModelC.create!
s.commit_transaction
end
Anyone know the reason?
Mongoid doesn't implement (or have) transactions at this time. That is a driver feature.
You shouldn't be calling commit_transaction as that is the first iteration of the transaction API exposed by the driver and doesn't support automatic retries. Mongoid documentation unfortunately hasn't yet been updated to show the correct API to use - it is the with_transaction method as described here.
To use a transaction on the driver level, the session that the transaction is started on must be passed to every operation manually, as shown in the same doc.
Mongoid doesn't have that requirement via what it calls a persistence context. This feature is somewhat described here, the gist of it is you can override where a model is read from or written to at runtime to e.g. write to another collection.
Sessions are implemented via this same runtime override. Review this page. The with_session method retrieves the client from the active persistence context, then ensures that 1) there is a session active on that client and 2) the active persistence context is associated with that session, so that 3) each persistence operation (read & write) would specify that session to the driver.
Now, to answer your question:
The thing I do not understand is the fact that I have to instantiate a session on a specific model or instance of a model.
Mongoid needs to know what client to start the session on. It can get that client from any persistence context. It doesn't matter if you use a model class or a model instance. Because only one session can be active at a time within Mongoid (the session is stored in thread-local storage for the current thread), you must use only models that are associated with the same client that you used for starting the session, via the with_session method, regardless of how that client is arrived at by Mongoid (be that via a model class or a model instance).

How to deal with Spring hibernate no lock aquired exception inside a transaction

I have applied #Transactional in my interface, and inside my serviceImpl, the corresponding method is calling some other methods, one method is reading, another method is writing. Although I have anotated as Transactional, when I am giving concurrent request, my insert method is throwing org.hibernate.exception.LockAcquisitionException: error.
Another problem is, this insert method is a shared method and it performs the insert method like Dao.save(obj) . Dao.save() is a generic method So i can not do anything here. I have to apply something on interface to avoid no lock aquired exception.
Is it possible to tell wait untill lock is aquired? Or retry if transaction is failed? Or lock all the tables until the transaction is completed so that another request can not access the relevent resources?
My hibernate version is 3.x, And database is mysql 5.6
The best way to do this is,
Mark your methods transactional
In your mysql database settings set the transaction isolation level as SERIALIZABLE

How can I get all open sessions?

Im using spring security and I would like to loop over all the open session and change the timeout using HttpSession.setMaxInactiveInterval(timeout);
I thought about using SessionRegistry.getAllSessions() but it only returns SessionInformation instances rather than HttpSession objects.
There isn't anything in Spring Security that will do this - as you observed, the SessionRegistry doesn't retain HttpSession instances.
So you'll have to maintain your own map of active sessions, using an HttpSessionListener to record session creation and destruction (pretty much as described in the answer to your question from yesterday.
It would probably be a Map<String,HttpSession> where the key is the session ID.
You can then iterate over that map any time you want and modify the session objects. Don't forget to use a thread-safe map and remove any sessions when they expire (in the sessionDestroyed method).

Inject Session object to DAO bean instead of Session Factory?

In our application we are using Spring and Hibernate.
In all the DAO classes we have SessionFactory auto wired and each of the DAO methods are calling getCurrentSession() method.
Question I have is why not we inject Session object instead of SessionFactory object in prototype scope? This will save us the call to getCurrentSession.
I think the first method is correct but looking for concrete scenarios where second method will throw errors or may be have bad performance?
When you define a bean as prototype scope a new instance is created for each place it needs to be injected into. So each DAO will get a different instance of Session, but all invocations of methods on the DAO will end up using the same session. Since session is not thread safe it should not be shared across multiple threads this will be an issue.
For most situations the session should be transaction scope, i.e., a new session is opened when the transaction starts and then is closed automatically once the transaction finishes. In a few cases it might have to be extended to request scope.
If you want to avoid using SessionFactory.currentSession - then you will need to define your own scope implementation to achieve that.
This is something that is already implemented for JPA using proxies. In case of JPA EntityManager is injected instead of EntityManagerFactory. Instead of #Autowired there is a new #PersistenceContext annotation. A proxy is created and injected during initialization. When any method is invoked the proxy will get hold of the actual EntityManager implementation (using something similar to SessionFactory.getCurrentSession) and delegate to it.
Similar thing can be implemented for Hibernate as well, but the additional complexity is not worth it. It is much simpler to define a getSession method in a BaseDAO which internally call SessionFactory.getCurrentSession(). With this the code using the session is identical to injecting session.
Injecting prototype sessions means that each one of your DAO objects will, by definition, get it's own Session... On the other hand SessionFactory gives you power to open and share sessions at will.
In fact getCurrentSession will not open a new Session on every call... Instead, it will reuse sessions binded to the current session context (e.g., Thread, JTA Transacion or Externally Managed context).
So let's think about it; assume that in your business layer there is a operation that needs to read and update several database tables (which means interacting, directly or indirectly, with several DAOs)... Pretty common scenario right? Customarily when this kind of operation fails you will want to rollback everything that happened in the current operation right? So, for this "particular" case, what kind of strategy seems appropriate?
Spanning several sessions, each one managing their own kind of objects and bound to different transactions.
Have a single session managing the objects related to this operation... Demarcate the transactions according to your business needs.
In brief, sharing sessions and demarcating transactions effectively will not only improve your application performance, it is part of the functionality of your application.
I would deeply recommend you to read Chapter 2 and Chapter 13 of the Hibernate Core Reference Manual to better understand the roles that SessionFactory, Session and Transaction plays within the framework. It will also teach will about Units of work as well as popular session patterns and anti-patterns.

object does not return updated optimistic locking version

I've implemented optimistic locking and see that it is working fine. However, the object that is returned to my backing bean from the service has the previous version not the current one. If I do another "find" in another transaction I get the correct one. It's like the commit is happening after the transaction returns.
I'm using eclipseLink with Spring for transaction control.
How do you commit the transaction, and how do you return the object? If you are merging an object into the active EntityManager, then you need to return the object that you merge into, not from.

Resources