12

I am using Spring and Hibernate in my application and using Spring Transaction.

So I have a service layer with annotation @Transaction on methods and DAO layer having methods for database query.

@Transactional(readOnly = false)
public void get(){

}

The issue is when I want to save an object in the database,then I have to use session.flush() at the end of DAO layer method. Why?

I think if I have annotated @Transaction, then Spring should automatically commit the transaction on completion of the service method.

DAO layer :

public BaseEntity saveEntity(BaseEntity entity) throws Exception {
        try {
            Session session = sessionFactory.getCurrentSession();
            session.saveOrUpdate(entity);
            session.flush();
        } catch (HibernateException he) {
            throw new Exception("Failed to save entity " + entity);
        }
        return entity;
    }

Service layer :

    @Transactional(readOnly = false)
    public BaseEntity saveEntity(BaseEntity entity) throws Exception {
        return dao.saveEntity(entity);
    }

spring config :

<context:property-placeholder properties-ref="deployProperties" />

    <tx:annotation-driven transaction-manager="transactionManager" />   

    <!-- Activate Spring Data JPA repository support -->
    <jpa:repositories base-package="com" />

    <!-- Declare a datasource that has pooling capabilities-->   
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close"
        p:driverClass="${app.jdbc.driverClassName}"
        p:jdbcUrl="${app.jdbc.url}"
        p:user="${app.jdbc.username}"
        p:password="${app.jdbc.password}"
        p:acquireIncrement="5"
        p:idleConnectionTestPeriod="60"
        p:maxPoolSize="100"
        p:maxStatements="50"
        p:minPoolSize="10" />

    <!-- Declare a JPA entityManagerFactory -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" 
        p:persistenceXmlLocation="classpath*:META-INF/persistence.xml"
        p:persistenceUnitName="hibernatePersistenceUnit"
        p:dataSource-ref="dataSource"
        p:jpaVendorAdapter-ref="hibernateVendor"/>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
        p:dataSource-ref="dataSource" p:configLocation="${hibernate.config}"
        p:packagesToScan="com" />

    <!-- Specify our ORM vendor -->
    <bean id="hibernateVendor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                p:showSql="false"/>

    <!-- Declare a transaction manager-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" 
        p:entityManagerFactory-ref="entityManagerFactory"/>
Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
Ankit Gupta
  • 2,529
  • 2
  • 15
  • 26
  • 2
    spring does it for you, and `readonly=false` is default, you don't have declare it – Jaiwo99 Sep 30 '14 at 12:53
  • I think automatic commit doesn't intend to flush `Session` to DB immediately, but making the changes done in that transaction available to other transactions working with the same `Session`. – Alexey Malev Sep 30 '14 at 12:55
  • 1
    If you would have properly setup transactions then yes... But your setup is flawed. Why are you using both a `SessionFactory` and `EntitymanagerFactory`? You are only using a single transaction manager. The main issue is your setup. – M. Deinum Oct 25 '16 at 12:40
  • Yup, agree with @M.Deinum, you are using a SessionFactory that's not tied to the Spring TransactionManager. So, spring is not taking care of your transactions in your setup. – Sashi Aug 05 '17 at 11:04

2 Answers2

6

Yes, if you have @Transactional for your DAO method then you need not flush the session manually, hibernate will take care of flushing the session as part of committing the transaction if the operations in the method are successful.

Check this link to know on how @Transactional works - Spring - @Transactional - What happens in background?

Community
  • 1
  • 1
Chaitanya
  • 15,403
  • 35
  • 96
  • 137
  • Thank you,but without session.flush,updates are not reflected in databases,am i missing something? – Ankit Gupta Oct 01 '14 at 05:20
  • 1
    I didn't get you, can you elaborate what you mean? – Chaitanya Oct 01 '14 at 05:34
  • If i don't write session.flush in dao layer then records are not getting saved in database while it should be, as i am using @transactional in service layer,so is there any configuration issue or anything else? – Ankit Gupta Oct 01 '14 at 06:41
  • Spring should take care of flushing the session and committing the transaction. It seems you are doing something wrong in DAO layer itself, can you add code what you have in DAO layer then we can see why the issue is coming. – Chaitanya Oct 01 '14 at 06:45
  • `sessionFactory` in your DAO layer is injected by Spring only? – Chaitanya Oct 01 '14 at 09:18
0

By default, hibernate stacks its queries so they can be optimized when they are finally executed onto the database.

The whole point of flush is to flush this stack and execute it in your transaction onto the database. Your leaving the "safe" house of the JVM and execute your query on a big strange database.

This is why you can't select something you've just saved without a flush. It's simply not in the database yet.

The meaning of commit is to end the transaction and make changes of the database visible for others. Once commit has been executed there's no return possible anymore.

Frankly I'm not exactly sure if it is a best practice but for normal CRUD operations you should be able to add flush into your DAO layer. This way you don't need to worry about it into the service layer.

If you want java to optimize your transaction then you'll have to add it into your service layer. But remember that you don't need to solve performance issues when there aren't any! Flushes all over your code into the service layer is not good for the code readability. Keep it simple and stupid ;)

Nishi
  • 10,634
  • 3
  • 27
  • 36