Search code examples
javahibernatetransactionsglassfishseam

How to force a new record to be saved to the database *immediately*?


I'm developing a Java/Seam/Hibernate/Glassfish application with two threads:

  • Thread #1 sends various messages and writes summary information to a MySQL database.
  • Thread #2 polls the database periodically (invoked by a ScheduledExecutorService) and acts on the current "state" of each message.

Have come across an integration test problem: It doesn't seem to matter how long Thread #2 waits for a new row to be added by Thread #1, it just isn't added during the test so the expected call isn't made. Then sure enough, after the test has failed a new row pops up - but too late. Not sure if this might be a design problem - Thread #2 currently gets a Seam context using Lifecycle.beginCall()...Lifecycle.endCall(). So my understanding (which may be wrong) is possibly the problems are due to there being two separate Hibernate sessions for the two threads - so the one reading doesn't know about the latest information from the one writing?

There may be different ways of fixing this but my current thinking is couldn't I just force Hibernate to actually add a record to the table immediately when I call save() / flush() or even manually commit a transaction? No luck with any of these - makes me wonder if there is some kind of managed transaction being used behind the scenes. Grateful for any advice...

For info, here's the gist of the code that adds a record:

// Obtain Hibernate session
Session session = (Session) Component.getInstance("hibernateSession");

// Create request
Request newRequest = new Request();
// newRequest.set<blah>();

// Save the new request to the database
session.save(newRequest);

// Have tried session.flush(), transaction.commit() etc. here.
// Nothing seems to put the record into the database straight away.

Not sure if this is relevant but here is the Hibernate configuration:

<property name="transaction.flush_before_completion">true</property>
<property name="connection.release_mode">after_statement</property>
<property name="transaction.manager_lookup_class">org.hibernate.transaction.SunONETransactionManagerLookup</property>
<property name="transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
<property name="current_session_context_class">jta</property>

(As this is an existing application owned by the customer I don't have the right to change the Hibernate config.)


Solution

  • Your guess is good.

    You are using a JTATransactionFactory, so the transaction is demarcated by JTA (i.e by the container).

    The method you are using to save the Request (here I presume it is defined in an EJB ) needs to be annotated with a transactional annotation: @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW), so when the method ends, the transaction gets committed.