Session interface is a single threaded object between Java application and the persistence layer. Session opens a single database connection when it is created, and holds onto it until the session is closed. It is mainly to offer CRUD operations on the persistent object which is loaded by Hibernate from the database.
More details, in hibernate, Session interface wraps a JDBC connection, holds a mandatory (first-level) cache of persistent objects, allows Hibernate to automatically persist objects that are modified, and allows Hibernate to implement functionality such as lazy-loading.
State of persistent object
Persistent objects should be in one of the following three states at a given point in time:
transient: A new instance of a persistent class which is not associated with a Session and has no representation in the database and no identifier value. (ex. Person p = new Person). You can make a transient instance persistent by associating it with a Session.
persistent: A persistent instance has a representation in the database, an identifier value and is associated with a Session.
detached: Once we close the Hibernate Session, the persistent instance will become a detached instance. But the reference of the object is still valid. You could continue to modify the object. These changes will not lost and will be inserted into database when associated with a Session which changes it back to persistent state.
Open a session
Different version of Hibernate has different way to do it. The following is for Hibernate 4.3 only
To open a session, it’s better to create an util class:
getCurrentSession(), it needs to add in hibernate.cfg.xml:
openSession vs getCurrentSession
- We can use it when we decided to manage the Session our self.
- It does not try to store or pull the session from the current context. Just a brand new one.
- If we use this method, we need to
close()the session. It does not flush and close() automatically.
The “CurrentSession” refers to a Hibernate Session bound by Hibernate behind the scenes, to the transaction scope. It creates a brand new session if does not exist or uses an existing one if one already exists. It automatically configured with both auto-flush and auto-close attributes as true means Session will be automatically flushed and closed. It’s better to use
getCurrentSession() method when our transaction runs long time or with multi calls of session.
save() results in an SQL INSERT. It persists the given transient instance, first assigning a generated identifier. In brief, it adds/saves a new entity into database.
But be careful here,
save() does not guarantee the same, it returns an identifier, and if an INSERT has to be executed to get the identifier, this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context.
persist() also makes a transient instance persistent. However, it doesn’t guarantee that the identifier value will be assigned to the persistent instance immediately, the assignment might happen at flush time. It also guarantees that it will not execute an
INSERT statement if it is called outside of transaction boundaries. This is useful in long-running conversations with an extended Session/persistence context.
load() and get()
get() result in an SQL
SELECT BY ID. It returns the persistent instance of the given entity class with the given identifier.(
load() returna a “proxy”)
Different between load() and get()
load()returns a “proxy” without hitting the database (lazy loading). In Hibernate, proxy is an object with the given identifier value, its properties are not initialized yet, it just look like a temporary fake object. If no row found , it will throws an exception - ObjectNotFoundException.
get()always hits the database and returns the real object instead of a proxy. If no row found , it return null.
Which one to use
If I’m not sure whether the object exists or not, I use
get() to avoid an exception. If I’m sure, I prefer
update() and saveOrUpdate()
Which function will result in SQL
UPDATE? We could find
saveOrUpdate(). But we need to know firstly, there is no need to call these functions to do update. When we
get()/load() a persistent object, and then call setters to modify something. After transaction
commit() or session
flush(). Database will be updated.
So why we need
update()? In fact, it’s mainly used to updated a detached object which was ever a persistent object and now session is closed. When
update() a detached object, it will become persistent again.
It means either
update() the given instance on the basis of identifier exists or not. When we are not sure whether the instance was ever persistent (so whether an identifier exists or not). USE IT! If the instance has an identifier,
update() will be run to update it in databas. If no identifier,
save() will be run to add an identifier and insert it into database.
merge() is also used to update a detached object. It copies the state of the given object onto the persistent object with the same identifier.
The difference with
update() is that
update() tries to reattach the instance, meaning that there is no other persistent object with the same identifier attached to the Session right now otherwise NonUniqueObjectException is thrown.
merge(), however, just copies all values to a persistent instance in the Session (which will be loaded if it is not currently loaded). The input object is not changed. So merge is more general than
update(), but may use more resources.
So if in this situation, we should use
merge(), it needs to merge user1 with user2:
So here merge returns the same reference of user2.
delete() results in SQL
ind() in current version! We must use query or criteria to achieve it.
session.flush() forces Hibernate to synchronize the in-memory state of the Session with the database.
By default, Hibernate will flush changes automatically for you:
- Before some query executions
- When a transaction is committed
We could also set flush mode, by default is AUTO:
Be careful, setFlushMode() must be invoked before session.beginTransaction().