Hibernate Session vs Transaction - java

I'm a bit confused about the concept of Sessions and Transactions in Hibernate.
As far as i understand, Hibernate uses Sessions (Persistence Context), which is basically a Cache for Entitys that need to be persist, deleted or whatever in the Database.
Sessions encapsulate Transactions, so i start a Session, followed by creating a Transaction. After the Transaction is closed, everything from the Persistence Context is flushed to the Database.The same thing will happen, if i close the Session.
Why do i need both? Can i do the same without creating a Transaction?

First of all, you can open more than 1 transaction within the same session.
Now, flushing doesn't necessarily relate to transaction commit. When you save() an entity - it'll be flushed if you use Identity generation strategy. When you select something - Session will also flush (if flush mode is AUTO). And you can even tell Hibernate not to flush before transaction commits (flush mode MANUAL).
Transactions are only responsible for ACID, it's a DB feature. While Session is responsible for managing entities, generating SQL, handling events. It's a Java thing.
PS: Session isn't just a "cache". It's also a way to track which entities are changed. So it's more than just an optimization trick.

Related

Hibernate first level cache and get method

I have read that the session.get(Employee.class, new Long(1)) method will take the data from cache or database.
If there are two users who are accessing the application concurrently.
if user - > User1 is doing get then data will be retrieved from DB. Now data is moved to cache.
If user - > User2 has deleted the record or updated the record. then
If user - > User1 is doing get then data will it be retrieved from cache.
Isnt User1 is getting old data. Does it falls to pitfall of caching.
Or am I missing something here?
I can say on this that why User1 is doing 2 times session.get in the same session. But still I need different opinions.
You understand it correctly: the cache is bound to the session, and if an object is loaded into the first-level cache, then no SQL will executed with #get(). You could use #evict() to clear one object from the cache, or #clear() to clear every object from the cache, without closing the session. Closing the session will always delete the entire cache.
See a nice explanation here.
You need to read more about Container-managed entity manager
The most common and widely used entity manager in a Java EE
environment is the container-managed entity manager. In this mode, the
container is responsible for the opening and closing of the entity
manager (this is transparent to the application). It is also
responsible for transaction boundaries. A container-managed entity
manager is obtained in an application through dependency injection or
through JNDI lookup, A container-managed entity manger requires the
use of a JTA transaction.
It's responable of what do you want understand and archive and how is used it.
More doucmentation Entity Mananger
No, because Hibernate saves data on cache, but whether you update the data with Hibernate it will know that some change exists. You will have troubles if you update the data with SQL or from other point where Hibernate cannot see that something happends.

Application managed JPA, when is Transaction needed

We are working on a little web (will run on Tomcat) with the data layer done with JPA (Eclipselink).
I did similar thing some time ago. But i were always unsure when i need to begin and end transactions or do a flush.
At the moment i use transaction if i add (persist) and remove objects. If i call setters on an already persisted object i do not use transactions.
Is there a guide/ tutorial or a short answer when to use transactions or how to implement application managed JPA correctly.
I think one can summarize an answer to your question.
almost any JPA operation needs a transaction, except find/selects that do not lock entities (i.e any JPA operation that does not change the data).
(JTA transaction-scoped entity manager)
In the case of an JTA transaction-scoped entity manager it is better to quote from the spec (Chapter 3 Entity Operations):
The persist, merge, remove, and refresh methods must be invoked within
a transaction context when an entity manager with a
transaction-scoped persistence context is used.
If there is no transaction context, the javax.persistence.TransactionRequiredException is thrown.
Methods that specify a lock mode other than LockModeType.NONE must be invoked
within a transaction context.
If there is no transaction context, the javax.persistence.TransactionRequiredException is thrown.
The find method (provided it is invoked without a lock or invoked with
LockModeType.NONE) and the getReference method are not required to be
invoked within a transaction context. If an entity manager with
transaction-scoped persistence context is in use, the resulting
entities will be detached; if an entity manager with an extended
persistence context is used, they will be managed. See section 3.3 for
entity manager use outside a transaction.
(Application-managed/resource-local entity manager)
In the case of an Application-managed entity manager, the JPA spec is not clear about the behavior. In the case of Hibernate, it is pretty complicated what happens, when not inside a transaction (it could depend also on the JDBC driver and the autocommit mode of the DB connection). Check Hibernate's article on this theme. Basically you are strongly encouraged to always use transactions for the above mentioned operations.
To the second part of your question: if you called a setter of a managed entity, and without flushing you detached it (i.e before transaction commit), the behavior is unclear/undefined, i.e you should better correct the code.
Example of buggy code:
//begin Transaction
MyEntity entity = em.find(MyEntity.class, 1L);
entity.setField("New value");
em.detach();//it is not sure whether the "New value" will be persisted. To make sure it is persisted, ypu need to call em.flush() before detaching
//commit Transaction
Usually if the order of DB operations (not the same as the order of enity manager operations) is not important, you can leave the JPA implementation to decide when to flush (e.g on transaction commit).

What does EntityManager.flush do and why do I need to use it?

I have an EJB where I am saving an object to the database. In an example I have seen, once this data is saved (EntityManager.persist) there is a call to EntityManager.flush(); Why do I need to do this? The object I am saving is not attached and not used later in the method. In fact, once saved the method returns and I would expect the resources to be released. (The example code does this on a remove call as well.)
if (somecondition) {
entityManager.persist(unAttachedEntity);
} else {
attachedEntityObject.setId(unAttachedEntity.getId());
}
entityManager.flush();
A call to EntityManager.flush(); will force the data to be persisted in the database immediately as EntityManager.persist() will not (depending on how the EntityManager is configured: FlushModeType (AUTO or COMMIT) by default is set to AUTO and a flush will be done automatically. But if it's set to COMMIT the persistence of the data to the underlying database will be delayed until the transaction is committed.
EntityManager.persist() makes an entity persistent whereas EntityManager.flush() actually runs the query on your database.
So, when you call EntityManager.flush(), queries for inserting/updating/deleting associated entities are executed in the database. Any constraint failures (column width, data types, foreign key) will be known at this time.
The concrete behaviour depends on whether flush-mode is AUTO or COMMIT.
So when you call EntityManager.persist(), it only makes the entity get managed by the EntityManager and adds it (entity instance) to the Persistence Context. An Explicit flush() will make the entity now residing in the Persistence Context to be moved to the database (using a SQL).
Without flush(), this (moving of entity from Persistence Context to the database) will happen when the Transaction to which this Persistence Context is associated is committed.
The EntityManager.flush() operation can be used the write all changes to the database before the transaction is committed. By default JPA does not normally write changes to the database until the transaction is committed. This is normally desirable as it avoids database access, resources and locks until required. It also allows database writes to be ordered, and batched for optimal database access, and to maintain integrity constraints and avoid deadlocks. This means that when you call persist, merge, or remove the database DML INSERT, UPDATE, DELETE is not executed, until commit, or until a flush is triggered.
EntityManager.flush() sends actual SQL commands to DB.
Persistence framework usually manages transactions behind the scene. So there is no guaranty that flushed queries will be successfully committed.
EntityManager.flush() is always called just before the transaction commit by persistence framework automatically behind the scene.
EntityManager.persist() only registers an entity to persistence context without sending any SQL statements to DB. That means you won't get auto generated IDs after persist(). You just pass persisted object and eventually after later flush() it gets ID. You can call flush() yourself to get those IDs earlier. But again it is not the end of transaction so it can be rolled back and even more: changes might be seen (via phantom reads) by other transactions/thread/processes/servers and then disappear depending on DB engine and isolation level of current and foreign transaction!

What is a database session?

I understand a general understanding of the concept of a database transaction. We access a database within transaction to ensure ACID properties.
In Hibernate there is a concept called a session. What is the use of a session? When should database access happen in two sessions rather than in the same session?
To explain more, I have seen hibernate code that
gets a session from a session factory
opens a session
begins a transaction
commits the transaction
closes the session
What I need to know is what is the importance of a session here? Why not have something like a transaction factory, begin transaction and commit transaction?
Session is more than just a transaction, it is an implementation of UnitOfWork pattern. In other words it holds on to the loaded objects, knows which objects has to be persisted etc:
A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.
To better understand relation between Session and Transaction you can take a look at this article.
A single Hibernate Session might have the same scope as a single database transaction.
This is the most common programming model used for the session-per-request implementation pattern. A single Session and a single database transaction implement the processing of a particular request event (for example, a Http request in a web application). Do never use the session-per-operation anti-pattern! (There are extremely rare exceptions when session-per-operation might be appropriate, you will not encounter these if you are just learning Hibernate.)
Another programming model is that of long Conversations, e.g. an application that implements a multi-step dialog, for example a wizard dialog, to interact with the user in several request/response cycles.
One way to implement this is the session-per-request-with-detached-objects pattern. Once persistent objects are considered detached during user think-time and have to be reattached to a new Session after they have been modified.
The session-per-conversation pattern is however recommended. In this case a single Session has a bigger scope than a single database transaction and it might span several database transactions. Each request event is processed in a single database transaction, but flushing of the Session would be delayed until the end of the conversation and the last database transaction, to make the conversation atomic. The Session is held in disconnected state, with no open database connection, during user think-time. Hibernate's automatic optimistic concurrency control (with versioning) is used to provide conversation isolation.
#Dmitry has answered very nicely.
Another way to look at the session is as Instance of Database Usage. When you create a session, you have a context ready for any database interaction with support services (e.g. transaction, caching, connection etc) required therein. A transaction is an independent service used within the session.
Also the session is the first level cache used by the typical OR mapping tools like hibernate. Session acts as temporary context created upon request to facilitate a DB interaction.

Does a Hibernate transaction rollback delete "session.flush()"ed entities?

I have been confused about transaction.rollback. Here is example pseudocode:
transaction = session.beginTransaction()
EntityA a = new EntityA();
session.save(a);
session.flush();
transaction.rollback();
What happens when this code works? Do I have the entity in the database or not?
Short answer: No, you won't have entity in the database.
Longer answer: hibernate is smart enough not to send insert/updates to the DB until it knows if the transaction is going to be committed or rolled back (although this behavior can be changed by setting a different FlushMode), in your case by calling flush you are forcing the SQL to be sent to the DB but you still have the DB transaction to protect you, when you call rollback the DB transaction will be rolled back removing the changes performed inside itself and hence nothing will be actually saved. Note that depending on your configured transaction isolation level perhaps other transactions will be able to see in some way the EntityA you saved for the short while between the save and the rollback.
Also note that flush is called automatically when you try to read from DB, in 99% of the cases calling it explicitly is not necessary. One exception that comes to mind is when unit testing with auto rolling back tests.
When you call session.save(a) Hibernate basically remembers somewhere inside session that this object has to be saved. It can decide if he wants to issue INSERT INTO... immediately, some time later or on commit. This is a performance improvement, allowing Hibernate to batch inserts or avoid them if transaction is rolled back.
When you call session.flush(), Hibernate is forced to issue INSERT INTO... against the database. The entity is stored in the database, but not yet commited. Depending on transaction isolation level it won't be seen by other running transactions. But now the database knows about the record.
When you call transaction.rollback(), Hibernate rolls-back the database transaction. Database handles rollback, thus removing newly created object.
Now consider the scenario without flush(). First of all, you never touch the database so the performance is better and rollback is basically a no-op. On the other hand if transaction isolation level is READ UNCOMMITTED, other transactions can see inserted record even before commit/rollback. Without flush() this won't happen, unless Hibernate does not decide to flush() implicitly.
I think you get confused with flush and commit.
flush() synchronizes the state with the database, but it is not doing a commit. The state is still visible by transaction, so that you can call rollback to rollback.
So the answer to your question is: no, you don't have the entity (a) in the database.

Categories