9

The problem is following code snippet doesn't delete the record in DB.

import org.hibernate.Session;
import org.hibernate.SessionFactory;
...
...
void deleteForm() {
   Session session = sessionFactory.openSession();
   FormDO formDO = new FormDO();
   formDO.setId(formId);
   session.delete(formDO); // No delete SQL query is getting fired. 

However, if I call session.flush() after delete, it works perfectly. Please note, I am NOT using any Transaction.

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.

And I have seen many code snippets online which shows that it is not necessary to call flush() after delete(). Similar question was raised in other forum here but it remained unanswered.

Also, session.save works fine without session.flush.

I am using Hibernate 4.2.16 + Spring 4.0.9 + JPA 1.0 annotations. Following are the source files for further reference,

FormDO.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="form")
    public class FormDO {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    Integer id;
    @Column(name="name")
    String name;
    ...
    ...

Spring Configuration File

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/tempdb" />
        <property name="username" value="root" />
        <property name="password" value="****" />
    </bean>
    <!-- Hibernate 4 SessionFactory Bean definition -->
    <bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.test.FormDO</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.current_session_context_class">thread</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

FormDAO.java

@Named
public class FormDAO {
    @Inject
    private SessionFactory sessionFactory;

    public boolean deleteForm(Integer formId) {
        Session session = sessionFactory.openSession();
        FormDO formDO = new FormDO();
        formDO.setId(formId);
        session.delete(formDO);
        session.flush(); // If this line is commented, record DOES NOT get deleted
        return true;
    }
    public boolean saveForm(FormDO formDO) { 
       Session session = sessionFactory.openSession();
       session.save(formDO); // Save doesn't require session.flush
       return true;
    }
    ...
    ...

UPDATE:

My dilemma was largely due to the inconsistency.. session.save was inserting the record immediately but session.delete doesn't reflect unless flush() was called explicitly. But when I refer the Flushing the Session link posted by Afsun, my doubts were cleared by reading following line,

An exception is that objects using native ID generation are inserted when they are saved.

I really appreciate the answers posted by everyone as almost all of them were pointing to the right direction but Afsun clears my doubt totally. Thanks!

Gaurang Patel
  • 4,310
  • 6
  • 27
  • 32

3 Answers3

7

From the Javadoc for the Hibernate Session class:

Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.

When you make your call to session.delete() you tell Hibernate to remove the entity from being managed. However, the corresponding record will still exist in the underlying database. You need to make the call to session.flush() in order to sync the database with the Hibernate session. Note that if your program were to end without your calling session.flush() then next time you start up the app again the entity in question would reappear.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
7

When your work with database via Hibernate you are using Hibernate session. Hibernate sessions flushed to the database by following three situations.

  1. commit()- When you commit a transaction
  2. Before you run a query
  3. When you call session.flush()

Here the most important is second. After every query does not Hibernate session flush database. If we run Native SQL Query via Hibernate,Hibernate does not know to flush the session or also if run HQL also Hibernate does not know to flush session. The call to flush will synchronise the session state with the database.

See the following: Hibernate flush before delete and Flushing the Session

Community
  • 1
  • 1
Afsun Khammadli
  • 2,048
  • 4
  • 18
  • 28
2

flush() This method forces current session to flush. Must be called at the end of a unit of work, before commiting the transaction and closing the session (depending on flush-mode, Transaction.commit() calls this method). Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.

Therefore it is necessary flush the session when you call delete or else the deleted record will still exist in the underlying database. Also you are not closing the sessions you are opening.This may be issue when you start using pooling mechanism. The best practice is in most cases session-per-request.Closing a session will always flush al work to the database.
Also you need to flush in batch processing otherwise it may give OutOfMemoryException.

Viraj Nalawade
  • 3,137
  • 3
  • 28
  • 44
  • Thanks for pointing out about session.close. As I have just begun writing this new code, I missed it. But anyway I would like to disagree with you when you say, 'Closing a session will always flush all work to the database.' I tried and it did not. Please refer below URL, http://stackoverflow.com/questions/3931162/will-hibernate-flush-my-updated-persistent-object-when-calling-session-close-w – Gaurang Patel May 14 '15 at 07:40
  • Thanks my assumption about close() calling flush() was wrong and yes its good practice to close a session. – Viraj Nalawade May 14 '15 at 07:56