Hibernation Problem / MySQL concurrency

I get an insanely strange result with Hibernate (4.1.9.Final) and MySQL (14.14. Mailing 5.5.29, InnoDB table):

When I save something to the database using one stream and try to retrieve it using another stream, Hibernate does not always find the object. (Even though I am committing the transaction correctly and closing persist-session before opening load-session.)

Some observations:

  • I cannot reproduce this with a single threaded program.

  • I can see the β€œmissing” object in the database and

  • If I restart the Hibernate application can successfully load the object.

Here is SSCCE illustrating the problem. (Import abbreviated for brevity):

public class StressTest { static SessionFactory sessionFactory; public static void main(String[] args) throws InterruptedException, ExecutionException { // Configure Hibernate Configuration conf = new Configuration(); conf.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect"); conf.configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder() .applySettings(conf.getProperties()) .buildServiceRegistry(); sessionFactory = conf.buildSessionFactory(serviceRegistry); // Set up producer / consumer BlockingQueue<Long> queue = new LinkedBlockingQueue<Long>(); new Consumer(queue).start(); new Producer(queue).start(); } } class DummyEntity { long id; public long getId() { return id; } public void setId(long id) { this.id = id; } } 

Manufacturer class (creates DummyEntities and saved).

 class Producer extends Thread { BlockingQueue<Long> sink; public Producer(BlockingQueue<Long> sink) { this.sink = sink; } @Override public void run() { try { while (true) { Session session = StressTest.sessionFactory.openSession(); DummyEntity entity = new DummyEntity(); entity.setId(new Random().nextLong()); session.beginTransaction(); session.save(entity); session.getTransaction().commit(); session.close(); sink.put(entity.getId()); } } catch (InterruptedException ignore) { System.exit(-1); } } } 

Consumer class (loads DummyEntities from the database):

 class Consumer extends Thread { BlockingQueue<Long> source; public Consumer(BlockingQueue<Long> source) { this.source = source; } @Override public void run() { try { while (true) { long entityId = source.take(); Session session = StressTest.sessionFactory.openSession(); Object entity = session.get(DummyEntity.class, entityId); session.close(); if (entity == null) { System.err.printf("Entity with id %d NOT FOUND", entityId); System.exit(-1); } } } catch (InterruptedException ignore) { System.exit(-1); } } } 

Finally, here is the xml mapping for DummyEntity .

 <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping default-cascade="all" default-lazy="false"> <class name="se.stresstest.DummyEntity"> <id name="id" type="long"> <generator class="assigned"/> </id> </class> </hibernate-mapping> 

The resulting output always ends with something like:

 Entity with id -225971146115345 NOT FOUND 

Any ideas why?

(This is an improved version of the previous question .)

+6
source share
2 answers

This behavior can be compatible with the REPEATABLE READ transaction isolation mode, which is the default transaction isolation mode for InnoDB:

http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read

If your application logic depends on the ability to see data captured in other transactions, after the start of the current transaction - through repeated readings (data can / will change as a result of manipulations in other transactions) - you must set the transaction isolation READ COMMITTED:

http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_read-committed

+1
source

use MySQL5InnoDBDialect instead.

0
source

All Articles