Question

I want to change a unique key from one entity object to another in one @Transaction method:

Entity oldone=dao.getEntity(oldid);
Entity newone=dao.getEntity(newid);
oldone.setBarcode(null);
dao.update(oldone); //free the unique key "barcode"
newone.setBarcode(barcode);
dao.update(newone); //set the unique key "barcode"

But this code throws: Duplicate entry for key 'barcode' Dubugging I found that after the first dao.update nothing changes in the database. I tryed to set the hibernate flushmode to "always" but didn't change:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
            <prop key="hibernate.show_sql">false</prop>             
            <prop key="hibernate.bytecode.use_reflection_optimizer">false</prop>
            <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.search.autoregister_listeners">false</prop>
            <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
            <prop key="hibernate.flushMode">always</prop>
        </props>
    </property>
</bean>

Why hibernate doesn't flush?

Was it helpful?

Solution

It seems that this Hibernate property is only a hint to Hibernate. See here and in Hibernate ORM Docs, where they say

Except when you explicitly flush(), there are absolutely no guarantees about when the Session executes the JDBC calls, only the order in which they are executed.

More to this, the FlushMode.ALWAYS enum value Javadoc states that

The Session is flushed before every query. This is almost always unnecessary and inefficient.

I'm not sure if by "query" they mean only a database interrogation (reads) or any kind of operation, including inserts, updates and deletes.

If I were you, I would explicitly place a session.flush() call after the first update. I know that declarative way is cleaner, but sometimes imperative programming makes your business safer.

OTHER TIPS

Force this session to flush. Must be called at the end of a unit of work, before committing the transaction and closing the session (depending on flush-mode, Transaction.commit() calls this method).

When making new objects persistent flush() and then clear() the session regularly in order to control the size of the first-level cache.

Batch Processing

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();

Look this.

IT States that When Tx.commit(); occurs then the Flush function is called. to No need to even Write that function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top