2013-04-17 11 views
6

dostaję szalenie dziwny wynik z hibernacji (4.1.9.Final) i MySQL (14,14 Distrib 05.05.29, tabela InnoDB):Hibernate/MySQL problem współbieżności

Kiedy utrzymują coś do bazy danych za pomocą jeden wątek i spróbuj go pobrać za pomocą innego wątku, Hibernate nie zawsze znajduje obiekt.

Niektóre obserwacje (pomimo faktu, że ja właściwie popełniającego transakcję i zamykanie utrzymywać sesję przed otwarciem obciążenia sesję.):

  • I nie można odtworzyć to za pomocą pojedynczego -tyty program.

  • I może zobaczyć „brakującą” podmiot w bazie danych, a

  • Gdybym ponownie uruchomić aplikację hibernacji może pomyślnie załadować podmiot.

Oto SSCCE ilustrujące problem. (Import pominięta dla zwięzłość):

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; } 
} 

klasa Producent (tworzy DummyEntities i utrzymuje je).

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); 
     } 
    } 
} 

klasa Konsumentów (ładunki DummyEntities z bazy danych):

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); 
     } 
    } 
} 

Wreszcie, oto mapping-xml dla 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> 

Wynikiem zawsze kończy się coś takiego:

Entity with id -225971146115345 NOT FOUND 

jakieś pomysły dlaczego?

(Jest to wyrafinowana wersja poprzedniej question.)

+0

Podałem odpowiedź na poprzednie pytanie, które również pasuje do tego pytania, proszę je sprawdzić. – didierc

+0

@ aioobe a co z innymi wersjami hibernacji i/lub MySQL – Eugene

+0

@Eugene, nie sądzę, że jest to problem Hibernacji i nie mam pod ręką innych wersji MySQL. Jeśli zmienię na PostgreSQL, wszystko działa poprawnie. – aioobe

Odpowiedz

0

użycie MySQL5InnoDBDialect zamiast.

+0

Dzięki za sugestię. Nie pomogło niestety. : - / – aioobe

1

Takie zachowanie może być zgodna z trybu izolacji transakcji powtarzalnych czytać, co zdarza się domyślny tryb izolacji transakcji dla InnoDB:

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

Jeśli logika aplikacji jest uzależniona jest w stanie zobaczyć dane popełnione w innych transakcjach po rozpoczęto bieżącą transakcję - kosztem powtarzalnych odczytów (dane mogą/będą zmieniać się w wyniku manipulacji w innych transakcjach) - należy ustawić izolację transakcji na CZYTA SIĘ ZOBOWIĄZANĄ:

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