When I try to delete an entry from a db, using
session.delete(object)
then I can the following:
1) If the row is present in DB then two SQL queries are getting executed: A select and then a delete
2) If the row is not present in the DB then only the select query is getting executed
But again this is not the case for update. Irrespective of the presence of DB row, only the update query is getting executed.
Please let me know why this kind of behaviour for delete operation. Isn't it a performance issue since two queries are getting hit rather than one?
Edit:
I am using hibernate 3.2.5
Sample code:
SessionFactory sessionFactory = new Configuration().configure("student.cfg.xml").buildSessionFactory(); Session session = sessionFactory.openSession(); Student student = new Student(); student.setFirstName("AAA"); student.setLastName("BBB"); student.setCity("CCC"); student.setState("DDD"); student.setCountry("EEE"); student.setId("FFF"); session.delete(student); session.flush(); session.close();
cfg.xml
<property name="hibernate.connection.username">system</property> <property name="hibernate.connection.password">XXX</property> <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521/orcl</property> <property name="hibernate.jdbc.batch_size">30</property> <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property> <property name="hibernate.cache.use_query_cache">false</property> <property name="hibernate.cache.use_second_level_cache">false</property> <property name="hibernate.connection.release_mode">after_transaction</property> <property name="hibernate.connection.autocommit">true</property> <property name="hibernate.connection.pool_size">0</property> <property name="hibernate.current_session_context_class">thread</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property>
hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.infy.model.Student" table="STUDENT"> <id name="id" column="ID"> <generator class="assigned"></generator> </id> <property name="firstName" type="string" column="FIRSTNAME"></property> <property name="lastName" type="string" column="LASTNAME"></property> <property name="city" type="string" column="CITY"></property> <property name="state" type="string" column="STATE"></property> <property name="country" type="string" column="COUNTRY"></property> </class>
Try doing a session. flush() to flush the session, or a session. evict() to remove the object from the session.
In a non-transactional environment, multiple rows can be deleted in a batch in Hibernate something like the following. Session session=HibernateUtils. getSessionFactory(). getCurrentSession(); session.
Using a specific criteria in a delete query Important: Use criteria to return only the records that you want to delete. Otherwise, the delete query removes every record in the table.
In JavaDoc of Session class the description of delete method is: Remove a persistent instance from the datastore. The argument may be an instance associated with the receiving Session or a transient instance with an identifier associated with existing persistent state.
The reason is that for deleting an object, Hibernate requires that the object is in persistent state. Thus, Hibernate first fetches the object (SELECT) and then removes it (DELETE).
Why Hibernate needs to fetch the object first? The reason is that Hibernate interceptors might be enabled (http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html), and the object must be passed through these interceptors to complete its lifecycle. If rows are delete directly in the database, the interceptor won't run.
On the other hand, it's possible to delete entities in one single SQL DELETE statement using bulk operations:
Query q = session.createQuery("delete Entity where id = X"); q.executeUpdate();
To understand this peculiar behavior of hibernate, it is important to understand a few hibernate concepts -
Hibernate Object States
Transient - An object is in transient status if it has been instantiated and is still not associated with a Hibernate session.
Persistent - A persistent instance has a representation in the database and an identifier value. It might just have been saved or loaded, however, it is by definition in the scope of a Session.
Detached - A detached instance is an object that has been persistent, but its Session has been closed.
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html#objectstate-overview
Transaction Write-Behind
The next thing to understand is 'Transaction Write behind'. When objects attached to a hibernate session are modified they are not immediately propagated to the database. Hibernate does this for at least two different reasons.
- To perform batch inserts and updates.
- To propagate only the last change. If an object is updated more than once, it still fires only one update statement.
http://learningviacode.blogspot.com/2012/02/write-behind-technique-in-hibernate.html
First Level Cache
Hibernate has something called 'First Level Cache'. Whenever you pass an object to save()
, update()
or saveOrUpdate()
, and whenever you retrieve an object using load()
, get()
, list()
, iterate()
or scroll()
, that object is added to the internal cache of the Session. This is where it tracks changes to various objects.
Hibernate Intercepters and Object Lifecycle Listeners -
The Interceptor interface and listener callbacks from the session to the application, allow the application to inspect and/or manipulate properties of a persistent object before it is saved, updated, deleted or loaded. http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html#d0e3069
This section Updated
Cascading
Hibernate allows applications to define cascade relationships between associations. For example, 'cascade-delete'
from parent to child association will result in deletion of all children when a parent is deleted.
So, why are these important.
To be able to do transaction write-behind, to be able to track multiple changes to objects (object graphs) and to be able to execute lifecycle callbacks hibernate needs to know whether the object is transient/detached
and it needs to have the object in it's first level cache before it makes any changes to the underlying object and associated relationships.
That's why hibernate (sometimes) issues a 'SELECT'
statement to load the object (if it's not already loaded) in to it's first level cache before it makes changes to it.
Why does hibernate issue the 'SELECT' statement only sometimes?
Hibernate issues a 'SELECT'
statement to determine what state the object is in. If the select statement returns an object, the object is in detached
state and if it does not return an object, the object is in transient
state.
Coming to your scenario -
Delete - The 'Delete' issued a SELECT statement because hibernate needs to know if the object exists in the database or not. If the object exists in the database, hibernate considers it as detached
and then re-attches it to the session and processes delete lifecycle.
Update - Since you are explicitly calling 'Update'
instead of 'SaveOrUpdate'
, hibernate blindly assumes that the object is in detached
state, re-attaches the given object to the session first level cache and processes the update lifecycle. If it turns out that the object does not exist in the database contrary to hibernate's assumption, an exception is thrown when session flushes.
SaveOrUpdate - If you call 'SaveOrUpdate'
, hibernate has to determine the state of the object, so it uses a SELECT statement to determine if the object is in Transient/Detached
state. If the object is in transient
state, it processes the 'insert'
lifecycle and if the object is in detached
state, it processes the 'Update'
lifecycle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With