2013-04-17 9 views
6

私は、Hibernate(4.1.9.Final)とMySQL(14.14按分5.5.29、InnoDBのテーブル)でめちゃくちゃ奇妙な結果を得る休止/ MySQLの同時実行の問題

は、私が使用してデータベースに何かを持続あるスレッドで別のスレッドを使ってフェッチしようとすると、Hibernateは必ずしもそのエンティティを見つけるとは限りません。 (私は適切にトランザクションをコミットし、負荷のセッションを開く前に持続セッションを閉じていたという事実にもかかわらず。)

いくつかの所見:

  • 私はがシングルを使用して、これを再現することはできませんスレッドプログラム。

  • 私は、データベース内の「行方不明」の実体を見ることができ、そして

  • 私は、アプリケーションが成功したエンティティをロードすることができます休止状態再起動した場合

ここに問題を示すSSCCEがあります。 (輸入は簡潔にするために省略):

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

プロデューサークラスが(DummyEntitiesを作成し、それを持続します)。

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クラス(データベースからロードDummyEntities):

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

は最後に、ここにDummyEntityのマッピング-XMLです。

Entity with id -225971146115345 NOT FOUND 

任意のアイデア理由:

<?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> 

結果の出力は常にのようなもので終わりますか?

(これは前questionの洗練されたバージョンです。)

+0

これまでの質問に答えてくれましたが、それをチェックしてください。 – didierc

+0

@aioobe hibernateおよび/またはMySQLの他のバージョンについては – Eugene

+0

@Eugene、それはHibernateの問題ではないと思います。他のMySQLバージョンは手元にありません。私がPostgreSQLに変更すると、すべて正常に動作します。 – aioobe

答えて

0

使用MySQL5InnoDBDialect代わり。

+0

提案をありがとう。残念ながら助けてくれませんでした。 : - / – aioobe

1

この動作は、InnoDBのためのデフォルトのトランザクション分離モードであることを起こるREPEATABLE READのトランザクション分離モード、と一致することができます。

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

アプリケーションのロジックが見ることができることに依存している場合他のトランザクションでコミットされたデータの後に現在のトランザクションが開始されました - 反復可能な読み取り(データは他のトランザクションの操作の結果として変化する可能性があります)を犠牲にして、トランザクションの分離をREAD COMMITTEDに設定する必要があります。

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

関連する問題